MongoDB 컬렉션의 객체 배열에서 쿼리 된 요소 만 검색
내 컬렉션에 다음과 같은 문서가 있다고 가정합니다.
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
쿼리를 수행하십시오.
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
또는
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
일치하는 문서 (문서 1)를 반환 하지만 항상 모든 배열 항목을 포함합니다 shapes
.
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
그러나 다음 을 포함하는 배열로만 문서 (문서 1) 를 얻고 싶습니다 color=red
.
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
어떻게해야합니까?
MongoDB 2.2의 새로운 $elemMatch
프로젝션 연산자는 첫 번째로 일치하는 shapes
요소 만 포함하도록 반환 된 문서를 변경하는 다른 방법을 제공합니다 .
db.test.find(
{"shapes.color": "red"},
{_id: 0, shapes: {$elemMatch: {color: "red"}}});
보고:
{"shapes" : [{"shape": "circle", "color": "red"}]}
2.2에서는을 사용하여이 작업을 수행 할 수도 있습니다 $ projection operator
. 여기서 $
투영 객체의 필드 이름은 쿼리에서 필드의 첫 번째 일치하는 배열 요소의 인덱스를 나타냅니다. 다음은 위와 동일한 결과를 반환합니다.
db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});
MongoDB 3.2 업데이트
3.2 릴리스부터는 새로운 $filter
집계 연산자를 사용하여 프로젝션 중에 배열을 필터링 할 수 있습니다 . 첫 번째 배열 대신 모든 일치 항목 을 포함시킬 수 있다는 이점이 있습니다.
db.test.aggregate([
// Get just the docs that contain a shapes element where color is 'red'
{$match: {'shapes.color': 'red'}},
{$project: {
shapes: {$filter: {
input: '$shapes',
as: 'shape',
cond: {$eq: ['$$shape.color', 'red']}
}},
_id: 0
}}
])
결과 :
[
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
]
MongoDB 2.2+ 의 새로운 Aggregation Framework 는 Map / Reduce의 대안을 제공합니다. $unwind
연산자 별도하는 데 사용할 수있는 shapes
정합 될 수있는 문서의 스트림으로 배열 :
db.test.aggregate(
// Start with a $match pipeline which can take advantage of an index and limit documents processed
{ $match : {
"shapes.color": "red"
}},
{ $unwind : "$shapes" },
{ $match : {
"shapes.color": "red"
}}
)
결과 :
{
"result" : [
{
"_id" : ObjectId("504425059b7c9fa7ec92beec"),
"shapes" : {
"shape" : "circle",
"color" : "red"
}
}
],
"ok" : 1
}
주의 : 이 답변은 MongoDB 2.2 이상의 새로운 기능이 도입되기 전에 당시 관련 솔루션을 제공합니다 . 최신 버전의 MongoDB를 사용하는 경우 다른 답변을 참조하십시오.
필드 선택기 매개 변수는 완전한 특성으로 제한됩니다. 배열의 일부를 선택하는 데 사용할 수 없으며 전체 배열 만 선택할 수 있습니다. $ positional operator 사용하려고 시도했지만 작동하지 않았습니다.
가장 쉬운 방법은 클라이언트 에서 도형 을 필터링하는 것 입니다.
실제로 MongoDB에서 직접 올바른 출력 이 필요한 경우 map-reduce 를 사용 하여 모양을 필터링 할 수 있습니다 .
function map() {
filteredShapes = [];
this.shapes.forEach(function (s) {
if (s.color === "red") {
filteredShapes.push(s);
}
});
emit(this._id, { shapes: filteredShapes });
}
function reduce(key, values) {
return values[0];
}
res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })
db[res.result].find()
또 다른 중요한 방법은 MongoDB 2.6 의 새로운 집계 기능 중 하나 인 $ redact 를 사용 하는 것입니다 . 2.6을 사용하는 경우 큰 배열이있는 경우 성능 문제를 일으킬 수있는 $ unwind가 필요하지 않습니다.
db.test.aggregate([
{ $match: {
shapes: { $elemMatch: {color: "red"} }
}},
{ $redact : {
$cond: {
if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}]);
$redact
"문서 자체에 저장된 정보를 기반으로 문서의 내용을 제한합니다" . 따라서 문서 내부 에서만 실행됩니다 . 기본적으로 문서를 맨 아래까지 스캔하고에있는 if
조건 과 일치하는지 확인합니다. 일치하는 $cond
경우 content ( $$DESCEND
) 또는 remove ( $$PRUNE
)를 유지합니다 .
위의 예에서 먼저 $match
전체 shapes
배열을 반환 하고 $ redact는 배열을 예상 결과로 제거합니다.
참고 {$not:"$color"}
그것뿐만 아니라 상단의 문서를 스캔하기 때문에, 필요하며, 경우 $redact
찾을 수없는 color
최고 수준에 필드를이 반환됩니다 false
그것이 우리가 원하지 않는 문서 전체를 제거 할 수도 있습니다.
배열 $slice
에서 중요한 객체를 반환하는 것이 도움이되므로 배열 요소를 일치시키는 쿼리를 더 잘 수행 할 수 있습니다 .
db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})
$slice
요소의 색인을 알고 있지만 때로는 어떤 기준 요소와 일치하는 배열 요소를 원할 때 유용합니다. $
연산자 와 일치하는 요소를 반환 할 수 있습니다 .
db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})
출력
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
mongodb에서 find의 구문은 다음과 같습니다.
db.<collection name>.find(query, projection);
그리고 두 번째로 작성한 쿼리는
db.test.find(
{shapes: {"$elemMatch": {color: "red"}}},
{"shapes.color":1})
여기에서는 $elemMatch
쿼리 부분에서 연산자를 사용했지만 투영 부분에서이 연산자를 사용하면 원하는 결과를 얻을 수 있습니다. 검색어를 다음과 같이 작성할 수 있습니다
db.users.find(
{"shapes.color":"red"},
{_id:0, shapes: {$elemMatch : {color: "red"}}})
원하는 결과를 얻을 수 있습니다.
JohnnyHK 에게 감사합니다 .
여기에 좀 더 복잡한 사용법을 추가하고 싶습니다.
// Document
{
"_id" : 1
"shapes" : [
{"shape" : "square", "color" : "red"},
{"shape" : "circle", "color" : "green"}
]
}
{
"_id" : 2
"shapes" : [
{"shape" : "square", "color" : "red"},
{"shape" : "circle", "color" : "green"}
]
}
// The Query
db.contents.find({
"_id" : ObjectId(1),
"shapes.color":"red"
},{
"_id": 0,
"shapes" :{
"$elemMatch":{
"color" : "red"
}
}
})
//And the Result
{"shapes":[
{
"shape" : "square",
"color" : "red"
}
]}
당신은 단지 쿼리를 실행해야합니다
db.test.find(
{"shapes.color": "red"},
{shapes: {$elemMatch: {color: "red"}}});
이 쿼리의 출력은
{
"_id" : ObjectId("562e7c594c12942f08fe4192"),
"shapes" : [
{"shape" : "circle", "color" : "red"}
]
}
예상대로 배열에서 색상 : '빨간색'과 일치하는 정확한 필드를 제공합니다.
$ project와 함께 다른 현명한 일치 요소가 문서의 다른 요소와 함께 클럽 화되는 것이 더 적합합니다.
db.test.aggregate(
{ "$unwind" : "$shapes" },
{ "$match" : {
"shapes.color": "red"
}},
{"$project":{
"_id":1,
"item":1
}}
)
db.test.find( {"shapes.color": "red"}, {_id: 0})
'Programing' 카테고리의 다른 글
C ++ 템플릿 typedef (0) | 2020.03.01 |
---|---|
Spring MVC에서 @ModelAttribute는 무엇입니까? (0) | 2020.03.01 |
메소드를 정적으로 만들 수는 있지만 그렇게해야합니까? (0) | 2020.03.01 |
\ r \ n, \ r 및 \ n 그들 사이의 차이점은 무엇입니까? (0) | 2020.03.01 |
void 메소드가 예외를 던지는 Mockito 테스트 (0) | 2020.03.01 |