programing

배열 필드가 비어 있지 않은 MongoDB 레코드 찾기

i4 2023. 3. 22. 20:44
반응형

배열 필드가 비어 있지 않은 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: [] } })

값이 수 예: " " " ) 。null boolean또는 기타)를 사용하여 다음 답변에 제시된 바와 같이 체크를 추가합니다.

mongo > = 3.2의 경우:

ME.find({ pictures: { $exists: true, $type: 'array', $ne: [] } })

mongo < 3.2의 경우:

ME.find({ pictures: { $exists: true, $type: 4, $ne: [] } })

2. 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;DRdb.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요소가 , 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「3」의 「3」의 「3」의 「1」의 「1」의 「3」의 「1」의 「3」의 「3」의 문서는 되어 있습니다.pictures배열이 아닌 빈 배열이거나 누락된 배열입니다.

'그림'이 배열로 비어 있지 않은 문서만 모두 가져옵니다.

ME.find({pictures: {$type: 'array', $ne: []}})

3.2 이전 버전의 MongoDb를 사용하는 경우$type: 4$type: 'array'이 솔루션에서는 $size도 사용하지 않기 때문에 인덱스에 문제가 없습니다(쿼리는 쿼리의 $size 부분에 인덱스를 사용할 수 없습니다).

다음을 포함한 기타 솔루션(승인된 답변):

ME.find({그림: {$exists: true, $not: {$size: 0}}}}}); ME.find({그림: {$exists: true, $ne: []}}))

를 들어, 'displaces'가 다음과 같은 경우라도 문서를 반환하기 때문에 잘못된 것입니다.null,undefined 0 등

db.find({ pictures: { $elemMatch: { $exists: true } } })

$elemMatch배열 필드가 포함된 문서와 지정된 쿼리와 일치하는 요소가 하나 이상 일치합니다.

즉, 모든 어레이를 적어도 하나의 요소로 조합하는 것입니다.

이를 위해 다음 중 하나를 사용할 수 있습니다.
또한 둘 다 요청된 키가 없는 개체에 대한 결과를 반환하지 않도록 주의합니다.

db.video.find({pictures: {$exists: true, $gt: {$size: 0}}})
db.video.find({comments: {$exists: true, $not: {$size: 0}}})

하다를 사용하세요.$elemMatch:: " " "

$elemMatch 연산자는 배열 필드가 포함된 문서를 지정된 쿼리 조건 모두에 일치하는 요소를 하나 이상과 일치시킵니다.

$elemMatches는 값이 배열이며 비어 있지 않은지 확인합니다. 이런 을 하게 .

ME.find({ pictures: { $elemMatch: {$exists: true }}})

PS 이 코드의 변형은 MongoDB University의 M121 코스에서 볼 수 있습니다.

{ $where: "this.pictures.length > 1" }

$where를 사용하고 이것을 전달합니다.field_name.length는 어레이 필드의 크기를 반환하고 숫자와 비교하여 확인합니다. 어레이 크기보다 큰 값이 있는 어레이가 있으면 최소 1이어야 합니다. 따라서 모든 어레이 필드의 길이가 1보다 크면 해당 어레이에 일부 데이터가 있음을 의미합니다.

이것도 동작합니다.

db.getCollection('collectionName').find({'arrayName': {$elemMatch:{}}})

Mongo 연산자 $exists 위에 Exists 도우미 메서드를 사용할 수도 있습니다.

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

반응형