在数组字段不为空的地方findMongoDBlogging

我所有的logging都有一个名为“图片”的字段。 这个字段是一个string数组。

我现在想要这个数组不是空的最新的10个logging。

我已经search了一下,但奇怪的是,我还没有发现很多。 我读过$ where选项,但是我想知道原生函数有多慢,以及是否有更好的解决scheme。

即使如此,这是行不通的:

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

什么都不返回 离开this.pictures没有长度位的工作,但它也返回空logging,当然。

如果您还有没有钥匙的文件,您可以使用:

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

如果涉及到$ size,MongoDB不使用索引,所以这是一个更好的解决scheme:

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

此外,自从MongoDB 2.6发布以来,您可以与运营商$gt进行比较:

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

特别是在mongodb文件中,再加上一些令人困惑的东西,这个答案是:

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

这可能也适用于你:

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

从2.6版本开始,另一种方法是将该字段与一个空数组进行比较:

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

在shell中testing它:

 > 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至less有一个数组元素的文档,排除了pictures是一个空数组,而不是一个数组,或丢失的文档。

在查询时,您关心两件事情 – 准确性和性能。 考虑到这一点,我在MongoDB v3.0.14中testing了几种不同的方法。

TL; DR db.doc.find({ nums: { $gt: -Infinity }})是最快和最可靠的(至less在我testing的MongoDB版本中)。

build立

我插入1k文档w / o列表字段,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 }); 

我认识到这是不够的,像我在下面的testing中那样认真对待性能,但是足以呈现所选查询计划的各种查询和行为的正确性。

testing

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 } } 

你可以使用下面的任何一个来达到这个目的。
两者也都处理不返回没有请求键的对象的结果:

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

您也可以使用助手方法存在于Mongo运算符$ exists

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

这很简单,这对我有用。