ค้นหาระเบียน MongoDB โดยที่ฟิลด์อาร์เรย์ไม่ว่างเปล่า


502

บันทึกทั้งหมดของฉันมีเขตข้อมูลที่เรียกว่า "รูปภาพ" ฟิลด์นี้เป็นอาร์เรย์ของสตริง

ตอนนี้ฉันต้องการ 10 ระเบียนใหม่ล่าสุดที่อาร์เรย์นี้ไม่ว่างเปล่า

ฉันไปเที่ยวไปรอบ ๆ แต่ก็แปลกพอที่ฉันไม่ได้เจออะไรมากมาย ฉันได้อ่านตัวเลือก $ where แล้ว แต่ฉันสงสัยว่ามันช้าแค่ไหนสำหรับฟังก์ชั่นพื้นฐานและถ้ามีทางออกที่ดีกว่า

และถึงอย่างนั้นก็ไม่ได้ผล:

ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()

ไม่ส่งคืนอะไรเลย การออกไปthis.picturesโดยไม่ใช้บิตความยาวนั้นสามารถใช้งานได้

คำตอบ:


827

หากคุณมีเอกสารที่ไม่มีกุญแจคุณสามารถใช้:

ME.find({ pictures: { $exists: true, $not: {$size: 0} } })

MongoDB ไม่ใช้ดรรชนีถ้าเกี่ยวข้องกับขนาด $ ดังนั้นนี่เป็นทางออกที่ดีกว่า:

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

เนื่องจาก MongoDB 2.6 รีลีสคุณสามารถเปรียบเทียบกับโอเปอเรเตอร์$gtแต่อาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด (คุณสามารถหาคำอธิบายที่ไม่ได้รับคำอธิบายในคำตอบนี้ ):

ME.find({ pictures: { $gt: [] } })

6
สำหรับฉันนั่นเป็นวิธีการที่ถูกต้องเนื่องจากทำให้แน่ใจว่ามีอาร์เรย์อยู่และไม่ว่างเปล่า
LeandroCR

ฉันจะใช้ฟังก์ชันการทำงานเดียวกันได้อย่างไรโดยใช้mongoengine
Rohit Khatri

54
ระวังME.find({ pictures: { $gt: [] } })เป็นอันตรายแม้กระทั่งใน MongoDB รุ่นใหม่กว่า หากคุณมีดัชนีในเขตข้อมูลรายการของคุณและดัชนีนั้นถูกใช้ระหว่างการสืบค้นคุณจะได้รับผลลัพธ์ที่ไม่คาดคิด ตัวอย่างเช่นdb.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()ส่งกลับจำนวนที่เหมาะสมในขณะที่ผลตอบแทนdb.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count() 0
wojcikstefan

1
ดูคำตอบโดยละเอียดของฉันด้านล่างเพื่อเรียนรู้ว่าทำไมสิ่งนี้ถึงไม่เหมาะกับคุณ: stackoverflow.com/a/42601244/1579058
wojcikstefan

6
@ ความคิดเห็น wojcikstefan ของจะต้อง upvoted เพื่อป้องกันไม่ให้คนใช้ข้อเสนอแนะล่าสุดซึ่งภายใต้สถานการณ์บางอย่างจะไม่ส่งคืนเอกสารที่ตรงกัน
โทมัสจัง

181

หลังจากดูเพิ่มเติมโดยเฉพาะในเอกสาร mongodb และ puzzling บิตด้วยกันนี่คือคำตอบ:

ME.find({pictures: {$exists: true, $not: {$size: 0}}})

27
มันใช้งานไม่ได้ ฉันไม่รู้ว่ามันใช้งานได้ก่อนหน้านี้หรือไม่ แต่สิ่งนี้จะส่งคืนวัตถุที่ไม่มีปุ่ม 'รูปภาพ' ด้วย
rdsoze

17
ไม่น่าเชื่อว่าคำตอบนี้มี 63 upvotes เมื่อในความเป็นจริงสิ่งที่ @rdsoze กล่าวว่าเป็นความจริง - แบบสอบถามยังจะส่งกลับระเบียนที่ไม่ได้มีpicturesข้อมูล
Dan Dascalescu

5
โปรดใช้ความระมัดระวัง MongoDB จะไม่ใช้ดัชนีถ้า $ ขนาดมีส่วนเกี่ยวข้องเชื่อมโยง น่าจะดีกว่าถ้ารวม {$ ne: []} และอาจเป็น {$ ne: null}
Levente Dobson

17
@rdsoze บรรทัดแรกของคำถามรัฐ"ทั้งหมดของระเบียนของเราได้ข้อมูลที่เรียกว่า 'ภาพ'. ช่องนี้เป็นอาร์เรย์" ยิ่งไปกว่านั้นนี่เป็นสถานการณ์ที่สมบูรณ์และสมจริง คำตอบนี้ไม่ผิดมันใช้ได้กับคำถามที่เขียนอย่างแม่นยำและการวิพากษ์วิจารณ์หรือ downvoting เพราะความจริงที่ว่ามันไม่ได้แก้ปัญหาที่แตกต่างก็โง่
Mark Amery

1
@Cec เอกสารทั้งหมดบอกว่าถ้าคุณใช้ $ size ในแบบสอบถามมันจะไม่ใช้ดัชนีใด ๆ เพื่อให้ผลลัพธ์ที่รวดเร็วขึ้น ดังนั้นหากคุณมีดัชนีในเขตข้อมูลนั้นและคุณต้องการใช้ให้ยึดแนวทางอื่นเช่น {$ ne: []} ถ้ามันเหมาะกับคุณก็จะใช้ดัชนีของคุณ
Levente Dobson

108

สิ่งนี้อาจใช้ได้กับคุณ:

ME.find({'pictures.0': {$exists: true}});

2
ดี! นอกจากนี้ยังช่วยให้คุณตรวจสอบขนาดต่ำสุด คุณรู้หรือไม่ว่าอาร์เรย์มีการจัดทำดัชนีตามลำดับหรือไม่? จะมีกรณีที่pictures.2มีอยู่ แต่pictures.1ไม่ได้?
anushr

2
ตัว$existsดำเนินการเป็นบูลีนไม่ใช่ออฟเซ็ต @tenbatsu ควรจะใช้แทนtrue 1
ekillaby

2
@anushr Would there ever be a case where pictures.2 exists but pictures.1 does not? ใช่กรณีนั้นอาจเกิดขึ้นได้
Bndr

@TheBndr นั่นอาจเกิดขึ้นได้picturesก็ต่อเมื่อเป็นเอกสารย่อยไม่ใช่อาร์เรย์ เช่นpictures: {'2': 123}
JohnnyHK

4
นี้เป็นสิ่งที่ดีและใช้งานง่าย แต่ระวังว่าประสิทธิภาพการทำงานเป็นสิ่งสำคัญ - picturesมันจะทำคอลเลกชันสแกนแม้ว่าคุณจะมีดัชนีใน
wojcikstefan

35

คุณใส่ใจสองสิ่งในการสอบถาม - ความแม่นยำและประสิทธิภาพ โดยที่ในใจฉันทดสอบวิธีต่าง ๆ ใน MongoDB v3.0.14

TL; DR db.doc.find({ nums: { $gt: -Infinity }})เป็นวิธีที่เร็วและเชื่อถือได้มากที่สุด (อย่างน้อยใน MongoDB ที่ฉันทดสอบ)

แก้ไข: สิ่งนี้ไม่ทำงานใน MongoDB v3.6 อีกต่อไป! ดูความคิดเห็นภายใต้โพสต์นี้เพื่อหาแนวทางแก้ไข

ติดตั้ง

ฉันได้แทรกฟิลด์รายการเอกสาร 1k w / oa เอกสาร 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
  }
}

ขอบคุณสำหรับคำตอบโดยละเอียดของคุณ @wojcikstefan น่าเสียดายที่โซลูชันที่คุณแนะนำไม่ทำงานในกรณีของฉัน ฉันมีคอลเลกชัน MongoDB 3.6.4 พร้อมเอกสาร 2 ม. ส่วนใหญ่มีseen_eventsอาร์เรย์สตริงซึ่งมีการทำดัชนีด้วย ค้นหาด้วย{ $gt: -Infinity }ฉันได้รับเอกสาร 0 รายการทันที การใช้{ $exists: true, $ne: [] }ฉันได้รับเอกสารที่มีความเป็นไปได้สูงกว่า 1,2m เอกสารโดยเสียเวลาจำนวนมากในขั้นตอน FETCH: gist.github.com/N-Coder/b9e89a925e895c605d84bfeed648d82c
NCode

ดูเหมือนว่าคุณถูกต้อง @ รหัส - นี่ใช้งานไม่ได้กับ MongoDB v3.6 :( ฉันเล่นไปเรื่อย ๆ สองสามนาทีและนี่คือสิ่งที่ฉันพบ: 1. db.test_collection.find({"seen_events.0": {$exists: true}})ไม่ดีเพราะใช้การสแกนคอลเลกชัน 2. db.test_collection.find({seen_events: {$exists: true, $ne: []}})คือ ไม่ดีเนื่องจาก IXSCAN นั้นตรงกับเอกสารทั้งหมดแล้วจึงทำการกรองในเฟส FETCH ที่ช้า 3. เหมือนกันdb.test_collection.find({seen_events: {$exists: true, $not: {$size: 0}}})4. คำสั่งอื่น ๆ ทั้งหมดส่งคืนผลลัพธ์ที่ไม่ถูกต้อง
wojcikstefan

1
@NCode พบวิธีแก้ปัญหา! หากคุณมั่นใจว่าทั้งหมดไม่ว่างเปล่าประกอบด้วยสตริงคุณสามารถใช้นี้seen_events เพื่อยืนยันประสิทธิภาพดีตรวจสอบdb.test_collection.find({seen_events: {$gt: ''}}).count() db.test_collection.find({seen_events: {$gt: ''}}).explain(true).executionStatsคุณอาจบังคับให้เหตุการณ์ที่เห็นเป็นสตริงผ่านการตรวจสอบความถูกต้องของสคีมา: docs.mongodb.com/manual/core/schema-validation
wojcikstefan

ขอบคุณ! ค่าที่มีอยู่ทั้งหมดเป็นสตริงดังนั้นฉันจะลองดู นอกจากนี้ยังมีข้อผิดพลาดเกี่ยวกับปัญหานี้ในตัวแก้ไขข้อผิดพลาด MongoDB: jira.mongodb.org/browse/SERVER-26655
NCode

30

เริ่มต้นด้วยการเปิดตัว 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เป็นอาเรย์ที่ว่างเปล่าไม่ใช่อาเรย์หรือขาดหายไป


7
ระวังคำตอบนี้อาจทำให้คุณมีปัญหาหากคุณพยายามใช้ดัชนี การทำเช่นdb.ME.createIndex({ pictures: 1 })นั้นdb.ME.find({pictures: {$gt: []}})จะให้ผลลัพธ์เป็นศูนย์อย่างน้อยใน MongoDB v3.0.14
wojcikstefan

@wojcikstefan จับได้ดี จำเป็นต้องดูสดนี้
JohnnyHK

5

คุณสามารถใช้ข้อใดข้อหนึ่งต่อไปนี้เพื่อบรรลุเป้าหมาย
ทั้งคู่ยังดูแลไม่ส่งคืนผลลัพธ์สำหรับวัตถุที่ไม่มีรหัสที่ร้องขอในพวกเขา:

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

4

รับเอกสารทั้งหมดที่ 'รูปภาพ' เป็นอาร์เรย์และไม่ว่างเปล่า

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

ถ้าใช้รุ่น MongoDB ก่อน3.2ใช้แทน$type: 4 $type: 'array'โปรดสังเกตว่าโซลูชันนี้ไม่ได้ใช้ขนาด $ดังนั้นจึงไม่มีปัญหากับดัชนี ("แบบสอบถามไม่สามารถใช้ดัชนีสำหรับส่วนขนาด $ ของแบบสอบถาม")

โซลูชันอื่น ๆ รวมถึงเหล่านี้ (คำตอบที่ยอมรับ):

ME.find ({รูปภาพ: {$ มีอยู่: จริง, ไม่ใช่ $: {$ ขนาด: 0}}}); ME.find ({รูปภาพ: {$ มีอยู่: จริง, $ ne: []}})

มีความผิดเพราะพวกเขาส่งเอกสารแม้ว่าตัวอย่างเช่น 'ภาพ' เป็นnull, undefined, 0, ฯลฯ


2

ใช้$elemMatchโอเปอเรเตอร์: ตามเอกสารประกอบ

ตัวดำเนินการ $ elemMatch จับคู่เอกสารที่มีเขตข้อมูลอาร์เรย์ที่มีองค์ประกอบอย่างน้อยหนึ่งรายการที่ตรงกับเกณฑ์แบบสอบถามที่ระบุทั้งหมด

$elemMatchesทำให้แน่ใจว่าค่านั้นเป็นอาร์เรย์และไม่ว่างเปล่า ดังนั้นแบบสอบถามจะเป็นสิ่งที่ต้องการ

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

ป.ล. พบรหัสของตัวแปรนี้ในหลักสูตร M121 ของมหาวิทยาลัย MongoDB


0

นอกจากนี้คุณยังสามารถใช้วิธีผู้ช่วยที่มีอยู่มากกว่าตัวดำเนินการ Mongo ที่มีอยู่

ME.find()
    .exists('pictures')
    .where('pictures').ne([])
    .sort('-created')
    .limit(10)
    .exec(function(err, results){
        ...
    });

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

ใช้ $ where และส่ง this.field_name.length ซึ่งส่งคืนขนาดของฟิลด์ array และตรวจสอบโดยเปรียบเทียบกับตัวเลข ถ้าอาเรย์ใด ๆ มีค่าใด ๆ เกินขนาดอาเรย์จะต้องมีอย่างน้อย 1 ดังนั้นฟิลด์อาเรย์ทั้งหมดจะมีความยาวมากกว่าหนึ่งมันหมายความว่ามันมีข้อมูลบางอย่างในอาเรย์นั้น


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.