배열 필드가 비어 있지 않은 MongoDB 레코드 찾기
내 모든 기록에는 "사진"이라는 필드가 있습니다. 이 필드는 문자열 배열입니다.
이제이 배열이 비어 있지 않은 최신 10 개의 레코드를 원합니다.
나는 주변에서 봤지만 이상하게도 이것에 대해 많이 찾지 못했습니다. $ where 옵션을 읽었지만 네이티브 함수의 속도가 얼마나 느린 지, 더 나은 솔루션이 있는지 궁금합니다.
그럼에도 불구하고 작동하지 않습니다.
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
아무것도 반환하지 않습니다. this.pictures
길이 비트없이 남겨두면 작동하지만 물론 빈 레코드도 반환합니다.
키가없는 문서도있는 경우 다음을 사용할 수 있습니다.
ME.find({ pictures: { $exists: true, $not: {$size: 0} } })
MongoDB는 $ size가 관련된 경우 인덱스를 사용하지 않으므로 더 나은 솔루션이 있습니다.
ME.find({ pictures: { $exists: true, $ne: [] } })
MongoDB 2.6 릴리스 이후 연산자와 비교할 수 $gt
있지만 예기치 않은 결과가 발생할 수 있습니다 ( 이 답변에서 자세한 설명 을 찾을 수 있음 ).
ME.find({ pictures: { $gt: [] } })
특히 mongodb 문서와 수수께끼 같은 비트를 더 살펴본 후에 이것이 답이었습니다.
ME.find({pictures: {$exists: true, $not: {$size: 0}}})
이것은 또한 당신을 위해 일할 수 있습니다 :
ME.find({'pictures.0': {$exists: true}});
쿼리 할 때 정확도와 성능이라는 두 가지 사항에주의하십시오. 이를 염두에두고 MongoDB v3.0.14에서 몇 가지 다른 접근법을 테스트했습니다.
TL; DR db.doc.find({ nums: { $gt: -Infinity }})
은 가장 빠르고 안정적입니다 (최소한 테스트 한 MongoDB 버전).
편집 : 이것은 더 이상 MongoDB v3.6에서 작동하지 않습니다! 가능한 해결책은이 게시물 아래의 주석을 참조하십시오.
설정
목록 필드가있는 1k 개의 문서, 빈 목록이있는 1k 개의 문서 및 비어 있지 않은 목록이있는 5 개의 문서를 삽입했습니다.
for (var i = 0; i < 1000; i++) { db.doc.insert({}); }
for (var i = 0; i < 1000; i++) { db.doc.insert({ nums: [] }); }
for (var i = 0; i < 5; i++) { db.doc.insert({ nums: [1, 2, 3] }); }
db.doc.createIndex({ nums: 1 });
아래 테스트에서와 같이 성능을 심각하게 받아 들일 수있는 규모로는 충분하지 않지만 다양한 쿼리의 정확성과 선택한 쿼리 계획의 동작을 나타내는 것으로 충분합니다.
테스트
db.doc.find({'nums': {'$exists': true}})
잘못된 결과를 반환합니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': {'$exists': true}}).count()
1005
-
db.doc.find({'nums.0': {'$exists': true}})
올바른 결과를 반환하지만 전체 수집 스캔 ( COLLSCAN
설명의 통지 단계)을 사용하면 속도가 느려집니다 .
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums.0': {'$exists': true}}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums.0': {'$exists': true}}).explain()
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.doc",
"indexFilterSet": false,
"parsedQuery": {
"nums.0": {
"$exists": true
}
},
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"nums.0": {
"$exists": true
}
},
"direction": "forward"
},
"rejectedPlans": [ ]
},
"serverInfo": {
"host": "MacBook-Pro",
"port": 27017,
"version": "3.0.14",
"gitVersion": "08352afcca24bfc145240a0fac9d28b978ab77f3"
},
"ok": 1
}
-
db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}})
잘못된 결과를 반환합니다. 문서를 진행하지 않는 인덱스 검색이 잘못 되었기 때문입니다. 인덱스가 없으면 정확하지만 느릴 수 있습니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}}).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}}).explain('executionStats').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 2,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"nums": {
"$gt": {
"$size": 0
}
}
},
{
"nums": {
"$exists": true
}
}
]
},
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 0,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"({ $size: 0.0 }, [])"
]
},
"keysExamined": 0,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}})
올바른 결과를 반환하지만 성능이 좋지 않습니다. 기술적으로 인덱스 스캔을 수행하지만 여전히 모든 문서를 진행시킨 다음 필터링해야합니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}}).explain('executionStats').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2016,
"advanced": 5,
"needTime": 2010,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"nums": {
"$exists": true
}
},
{
"$not": {
"nums": {
"$size": 0
}
}
}
]
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2016,
"advanced": 5,
"needTime": 2010,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 2005,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 2005,
"executionTimeMillisEstimate": 0,
"works": 2015,
"advanced": 2005,
"needTime": 10,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"[MinKey, MaxKey]"
]
},
"keysExamined": 2015,
"dupsTested": 2015,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({'nums': { $exists: true, $ne: [] }})
올바른 결과를 반환하고 약간 더 빠르지 만 성능은 여전히 이상적이지 않습니다. IXSCAN을 사용하여 기존 목록 필드로 문서를 진행하지만 빈 목록을 하나씩 필터링해야합니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $ne: [] }}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $exists: true, $ne: [] }}).explain('executionStats').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 1018,
"advanced": 5,
"needTime": 1011,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"$not": {
"nums": {
"$eq": [ ]
}
}
},
{
"nums": {
"$exists": true
}
}
]
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 1017,
"advanced": 5,
"needTime": 1011,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 1005,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 1005,
"executionTimeMillisEstimate": 0,
"works": 1016,
"advanced": 1005,
"needTime": 11,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"[MinKey, undefined)",
"(undefined, [])",
"([], MaxKey]"
]
},
"keysExamined": 1016,
"dupsTested": 1015,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({'nums': { $gt: [] }})
사용 된 인덱스에 따라 결과가 예상치 못한 결과를 초래할 수 있으므로 위험합니다. 문서를 진행하지 않는 잘못된 인덱스 스캔 때문입니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $gt: [] }}).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $gt: [] }}).explain('executionStats').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"nums": {
"$gt": [ ]
}
},
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 0,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"([], BinData(0, ))"
]
},
"keysExamined": 0,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({'nums.0’: { $gt: -Infinity }})
올바른 결과를 반환하지만 성능이 저하됩니다 (전체 컬렉션 스캔 사용).
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums.0': { $gt: -Infinity }}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums.0': { $gt: -Infinity }}).explain('executionStats').executionStats.executionStages
{
"stage": "COLLSCAN",
"filter": {
"nums.0": {
"$gt": -Infinity
}
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2007,
"advanced": 5,
"needTime": 2001,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"direction": "forward",
"docsExamined": 2005
}
-
db.doc.find({'nums': { $gt: -Infinity }})
놀랍게도, 이것은 매우 잘 작동합니다! 올바른 결과를 제공하며 인덱스 스캔 단계에서 5 개의 문서를 빠르게 진행합니다.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': { $gt: -Infinity }}).explain('executionStats').executionStats.executionStages
{
"stage": "FETCH",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 16,
"advanced": 5,
"needTime": 10,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 5,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 15,
"advanced": 5,
"needTime": 10,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"(-inf.0, inf.0]"
]
},
"keysExamined": 15,
"dupsTested": 15,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
2.6 릴리스부터는 필드를 빈 배열과 비교하는 또 다른 방법이 있습니다.
ME.find({pictures: {$gt: []}})
쉘에서 테스트 :
> db.ME.insert([
{pictures: [1,2,3]},
{pictures: []},
{pictures: ['']},
{pictures: [0]},
{pictures: 1},
{foobar: 1}
])
> db.ME.find({pictures: {$gt: []}})
{ "_id": ObjectId("54d4d9ff96340090b6c1c4a7"), "pictures": [ 1, 2, 3 ] }
{ "_id": ObjectId("54d4d9ff96340090b6c1c4a9"), "pictures": [ "" ] }
{ "_id": ObjectId("54d4d9ff96340090b6c1c4aa"), "pictures": [ 0 ] }
따라서 pictures
하나 이상의 배열 요소가 있는 문서를 올바르게 포함하고 pictures
배열이 아닌 빈 배열이거나 누락 된 문서 는 제외합니다 .
이를 달성하기 위해 다음 중 하나를 사용할 수 있습니다.
둘 다 요청 된 키가없는 객체에 대한 결과를 반환하지 않도록주의합니다.
db.video.find({pictures: {$exists: true, $gt: {$size: 0}}})
db.video.find({comments: {$exists: true, $not: {$size: 0}}})
{ $where: "this.pictures.length > 1" }
$ where를 사용하고 배열 필드의 크기를 반환하는 this.field_name.length를 전달하고 숫자와 비교하여 확인하십시오. 모든 배열 필드의 길이가 둘 이상인 배열은 배열 크기보다 값이 1 이상이어야하는 경우 해당 배열에 데이터가 있음을 의미합니다.
'pictures'가 배열이고 비어 있지 않은 모든 문서 만 검색
ME.find({pictures: {$type: 'array', $ne: []}})
3.2 이전의 MongoDb 버전을 사용하는 경우 $type: 4
대신을 사용하십시오 $type: 'array'
. 이 솔루션은 $ size 조차 사용하지 않으므로 인덱스에는 문제가 없습니다 ( "쿼리는 쿼리의 $ size 부분에 인덱스를 사용할 수 없습니다").
다음을 포함한 다른 솔루션 (허용되는 답변) :
ME.find ({pictures : {$ exists : true, $ not : {$ size : 0}}}); ME.find ({사진 : {$ exists : true, $ ne : []}})
있습니다 잘못 그들은 예를 들어, 문서의 경우에도를 반환하기 때문에, '사진'이다 null
, undefined
0 등
설명서에 따라 $elemMatch
운영자를 사용하십시오.
$ elemMatch 연산자는 지정된 모든 쿼리 기준과 일치하는 요소가 하나 이상있는 배열 필드가 포함 된 문서를 일치시킵니다.
$elemMatches
값이 배열이고 비어 있지 않은지 확인하십시오. 그래서 쿼리는 다음과 같습니다
ME.find({ pictures: { $elemMatch: {$exists: true }}})
PS이 코드의 변형은 MongoDB University의 M121 과정에서 찾을 수 있습니다.
또한 도우미 메서드를 사용할 수 있음 몽고 운영자 $가 존재하는 이상
ME.find()
.exists('pictures')
.where('pictures').ne([])
.sort('-created')
.limit(10)
.exec(function(err, results){
...
});
ME.find({pictures: {$exists: true}})
그렇게 간단하지만 이것은 나를 위해 일했습니다.
참고 URL : https://stackoverflow.com/questions/14789684/find-mongodb-records-where-array-field-is-not-empty
'Programming' 카테고리의 다른 글
Maven 저장소에서 소스 JAR 가져 오기 (0) | 2020.02.18 |
---|---|
'정적'키워드는 클래스에서 무엇을합니까? (0) | 2020.02.18 |
jQuery 또는 getElementById와 같은 DOM 메소드가 요소를 찾지 못하는 이유는 무엇입니까? (0) | 2020.02.17 |
파이썬에서 배열을 선언하는 방법? (0) | 2020.02.17 |
이 사전 키가 C #에 있는지 어떻게 알 수 있습니까? (0) | 2020.02.17 |