중첩된 배열 내에서 일치하는 하위 문서 요소만 반환합니다.
주요 컬렉션은 소매점이며, 매장용 어레이를 갖추고 있습니다.각 스토어에는 다양한 오퍼가 준비되어 있습니다(이 스토어에서는 구입하실 수 있습니다).이 어레이에는 다양한 크기의 어레이가 있습니다(아래 예 참조).
에서, 「 」할 수 있는 오퍼를 .L
.
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"XS",
"S",
"M"
]
},
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"S",
"L",
"XL"
]
}
]
}
}
을 해봤습니다.db.getCollection('retailers').find({'stores.offers.size': 'L'})
다음과 같은 출력이 필요합니다.
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"S",
"L",
"XL"
]
}
]
}
}
그러나 "에는 "My Query"와 하지 않는 되어 있습니다.size
XS, X, M
어떻게 하면 MongoDB가 내 쿼리와 일치하는 오퍼만 반환하도록 강요할 수 있습니까?
안녕하세요, 감사합니다.
따라서 쿼리는 실제로 필요한 대로 "문서"를 선택합니다.그러나 반환되는 요소가 쿼리 조건에만 일치하도록 포함된 "배열 필터링"을 수행해야 합니다.
물론 이러한 세부사항을 걸러내 대역폭을 크게 절약하지 않는 한 시도조차 하지 말아야 합니다.최소한 첫 번째 위치일치를 넘어야 합니다.
MongoDB에는 쿼리 조건에서 일치하는 인덱스로 배열 요소를 반환하는 위치 연산자가 있습니다.다만, 대부분의 어레이 요소의 「외부」의 「최초의」일치 인덱스만 반환됩니다.
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$': 1 }
)
은 '', '마음', '마음', '마음', '마음', '마음',"stores"
어레이 위치만.따라서 "저장" 항목이 여러 개 있는 경우 일치하는 조건을 포함하는 요소 중 "하나"만 반환됩니다.하지만, 그것은 내부 배열에 아무런 도움이 되지 않는다."offers"
matchd 내의 "matchd는 "matchd"의 "matchd"에 되어 있습니다"stores"
이치노
MongoDB에는 표준 쿼리에서 이를 "필터링"하는 방법이 없기 때문에 다음 기능은 작동하지 않습니다.
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$.offers.$': 1 }
)
MongoDB가 실제로 이 수준의 조작을 수행할 수 있는 유일한 도구는 집약 프레임워크를 사용하는 것입니다.그러나 분석을 통해 "아마도" 이 작업을 수행하지 않고 코드로 어레이를 필터링해야 하는 이유를 알 수 있습니다.
버전별로 이 작업을 수행할 수 있는 순서입니다.
먼저 MongoDB 3.2.x를 사용하여 다음 작업을 수행합니다.
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$project": {
"stores": {
"$filter": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$filter": {
"input": "$$store.offers",
"as": "offer",
"cond": {
"$setIsSubset": [ ["L"], "$$offer.size" ]
}
}
}
}
}
},
"as": "store",
"cond": { "$ne": [ "$$store.offers", [] ]}
}
}
}}
])
다음으로 MongoDB 2.6.x 이후 및 을 사용하는 경우:
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$project": {
"stores": {
"$setDifference": [
{ "$map": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$setDifference": [
{ "$map": {
"input": "$$store.offers",
"as": "offer",
"in": {
"$cond": {
"if": { "$setIsSubset": [ ["L"], "$$offer.size" ] },
"then": "$$offer",
"else": false
}
}
}},
[false]
]
}
}
}
},
"as": "store",
"in": {
"$cond": {
"if": { "$ne": [ "$$store.offers", [] ] },
"then": "$$store",
"else": false
}
}
}},
[false]
]
}
}}
])
마지막으로 어그리게이션 프레임워크가 도입된 MongoDB 2.2.x 이상의 버전에서도 마찬가지입니다.
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$unwind": "$stores" },
{ "$unwind": "$stores.offers" },
{ "$match": { "stores.offers.size": "L" } },
{ "$group": {
"_id": {
"_id": "$_id",
"storeId": "$stores._id",
},
"offers": { "$push": "$stores.offers" }
}},
{ "$group": {
"_id": "$_id._id",
"stores": {
"$push": {
"_id": "$_id.storeId",
"offers": "$offers"
}
}
}}
])
설명을 분해해 봅시다.
MongoDB 3.2.x 이후
그래서 일반적으로는 목적을 염두에 두고 설계되어 있기 때문에 가는 길입니다.어레이에는 여러 레벨이 있으므로 각 레벨에 적용해야 합니다.그래서 먼저 각자에게 뛰어들어야 한다."offers"
의 범위 내에서"stores"
삼아 시험삼아 시험삼아 시험삼아 시험삼아 시험삼아 시험하다$filter
그 내용
여기서 간단하게 비교할 수 있는 것은 "Does the array is contained the element of I wanted" 입니다.이 논리적인 컨텍스트에서 간단히 할 수 있는 것은 동작을 사용하여 어레이('세트')를 비교하는 것입니다.["L"]
타겟 어레이에 접속합니다.서 그 은 " " " 입니다.true
「( 「L」을 포함한다).★★★★★★★★★★★★★★★★★★,"offers"
이치노
레벨의 「」에서는, 「」로 합니다.$filter
의 아, 아, 아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아아,아,아,아,아.$filter
배열이 되었습니다.[]
★★★★★★에"offers"
비어 있지 않으면 요소가 반환되거나 삭제됩니다.
MongoDB 2.6.x
만, 이 과정이 없는 . 이치노$filter
이 버전에서는 를 사용하여 각 요소를 검사한 후 를 사용하여 반환된 요소를 필터링할 수 있습니다.false
.
★★★★★★★★★★★★★★★★★.$map
하지만, 「」는 됩니다.$cond
할지 또는 를 반환할지 합니다.false
의 값$setDifference
나 to세세세세세세세세 " " " " "의 단일 요소 '세트[false]
.false
반환된 배열의 요소가 제거됩니다.
다른 모든 면에서 논리는 위와 같다.
MongoDB 2.2.x 이후
따라서 MongoDB 2.6 이하에서는 어레이를 사용하기 위한 유일한 도구는 입니다.이 목적으로만 어그리게이션 프레임워크를 "정당히" 사용할 수 없습니다.
각 어레이를 「분할」하는 것만으로, 불필요한 것을 걸러내고, 다시 조립하는 것으로, 프로세스는 심플하게 보입니다.주요 주의사항은 내부 어레이를 재구축하는 "첫 번째" 단계와 외부 어레이를 재구축하는 "두 가지" 단계입니다.구별되는 것이 있다_id
모든 수준에서 값을 지정하기 때문에 모든 그룹화의 모든 수준에 이러한 값을 포함하면 됩니다.
는 ★★★★★★★★★★★★★★★★★★★★★★★★.$unwind
비용이 많이 듭니다.목적은 있지만 문서별로 이러한 필터링을 하지 않는 것이 주된 사용 목적입니다.실제로 최신 릴리스에서는 어레이의 요소가 그룹화 키 자체의 일부가 되어야 할 경우에만 사용해야 합니다.
결론
따라서 이와 같은 어레이의 여러 레벨에서 일치하는 것을 얻는 것은 간단한 프로세스가 아닙니다.실제로 잘못 구현하면 비용이 매우 많이 들 수 있습니다.
는 쿼리 외에 입니다.$match
그것을요. 결과 인 형태의 '어느 정도'보다 더 ..find()
.
그러나 일반적으로 이러한 목록에는 여전히 복잡성이 있습니다.서버와 클라이언트 간에 사용되는 대역폭을 대폭 향상시키는 방법으로 필터링에 의해 반환되는 콘텐츠를 대폭 줄이지 않는 한,그러면 초기 쿼리 및 기본 투영 결과를 필터링할 수 있습니다.
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$': 1 }
).forEach(function(doc) {
// Technically this is only "one" store. So omit the projection
// if you wanted more than "one" match
doc.stores = doc.stores.filter(function(store) {
store.offers = store.offers.filter(function(offer) {
return offer.size.indexOf("L") != -1;
});
return store.offers.length != 0;
});
printjson(doc);
})
따라서 반환된 오브젝트 "post" 쿼리 처리를 사용하는 것은 집약 파이프라인을 사용하는 것보다 훨씬 덜 둔감합니다.또한 "실제"의 유일한 차이는 수신 시 "문서별" 삭제가 아닌 "서버" 상의 다른 요소를 폐기하는 것입니다.이로 인해 대역폭이 다소 절약될 수 있습니다.
하지만 당신이 현대판 발매에서 이 일을 하는 것이 아니라면 $match
★★★★★★★★★★★★★★★★★」$project
따라서 서버 처리의 '비용'은 일치하지 않는 요소를 먼저 제거함으로써 네트워크 오버헤드를 줄이는 '이득'을 크게 웃돌게 됩니다.
모든 경우에 동일한 결과를 얻을 수 있습니다.
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size" : [
"S",
"L",
"XL"
]
}
]
}
]
}
어레이가 내장되어 있기 때문에 $elemMatch를 사용할 수 없습니다. 대신 집계 프레임워크를 사용하여 결과를 얻을 수 있습니다.
db.retailers.aggregate([
{$match:{"stores.offers.size": 'L'}}, //just precondition can be skipped
{$unwind:"$stores"},
{$unwind:"$stores.offers"},
{$match:{"stores.offers.size": 'L'}},
{$group:{
_id:{id:"$_id", "storesId":"$stores._id"},
"offers":{$push:"$stores.offers"}
}},
{$group:{
_id:"$_id.id",
stores:{$push:{_id:"$_id.storesId","offers":"$offers"}}
}}
]).pretty()
이 쿼리는 배열(배열)을 해제한 다음 크기를 일치시킨 다음 문서를 이전 양식으로 재구성합니다.$group 스텝을 삭제하고 인쇄 방법을 확인할 수 있습니다.즐거운 시간 보내세요!
또, 집약 없이 동작합니다.솔루션 링크: https://mongoplayground.net/p/Q5lxPvGK03A
db.collection.find({
"stores.offers.size": "L"
},
{
"stores": {
"$filter": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$filter": {
"input": "$$store.offers",
"as": "offer",
"cond": {
"$setIsSubset": [
[
"L"
],
"$$offer.size"
]
}
}
}
}
}
},
"as": "store",
"cond": {
"$ne": [
"$$store.offers",
[]
]
}
}
}
})
언급URL : https://stackoverflow.com/questions/36229123/return-only-matched-sub-document-elements-within-a-nested-array
'programing' 카테고리의 다른 글
YAML 또는 JSON 언어 코드 목록 (0) | 2023.03.19 |
---|---|
Dropzone - 검출되지 않은 오류:URL이 제공되지 않았습니다. (0) | 2023.03.19 |
업로드 파일의 최대 크기를 설정하는 방법 (0) | 2023.03.19 |
레일 3의 JS/ERB 템플릿에서 JSON 처리 (0) | 2023.03.19 |
Angular를 사용하여 객체를 배열에 푸시하는 방법JS (0) | 2023.03.19 |