ske*_*rit 444 mongoose mongodb
我的所有记录都有一个名为"图片"的字段.该字段是一个字符串数组.
我现在想要这个数组不为空的最新10条记录.
我已经google了一下,但奇怪的是我在这方面找不到多少.我已经阅读了$ where选项,但我想知道本机函数有多慢,以及是否有更好的解决方案.
即便如此,这不起作用:
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
Run Code Online (Sandbox Code Playgroud)
什么都不返回 离开this.pictures没有长度位确实有效,但当然它也返回空记录.
Chr*_*is' 727
如果您还有没有密钥的文档,您可以使用:
ME.find({ pictures: { $exists: true, $not: {$size: 0} } })
Run Code Online (Sandbox Code Playgroud)
如果涉及$ size,MongoDB不使用索引,所以这是一个更好的解决方案:
ME.find({ pictures: { $exists: true, $ne: [] } })
Run Code Online (Sandbox Code Playgroud)
自MongoDB 2.6发布以来,您可以与运营商进行比较,$gt但可能会导致意外结果(您可以在此答案中找到详细说明):
ME.find({ pictures: { $gt: [] } })
Run Code Online (Sandbox Code Playgroud)
ske*_*rit 169
经过一番观察,特别是在mongodb文件中,以及令人费解的一点,这就是答案:
ME.find({pictures: {$exists: true, $not: {$size: 0}}})
Run Code Online (Sandbox Code Playgroud)
小智 102
这可能也适合你:
ME.find({'pictures.0': {$exists: true}});
Run Code Online (Sandbox Code Playgroud)
woj*_*fan 32
在查询时你关心两件事 - 准确性和性能.考虑到这一点,我在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 });
Run Code Online (Sandbox Code Playgroud)
我认识到这不足以像我在下面的测试中那样认真对待性能,但它足以呈现所选查询计划的各种查询和行为的正确性.
db.doc.find({'nums': {'$exists': true}}) 返回错误的结果(我们正在努力实现的目标).
MacBook-Pro(mongod-3.0.14) test> db.doc.find({'nums': {'$exists': true}}).count()
1005
Run Code Online (Sandbox Code Playgroud)
-
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
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
Run Code Online (Sandbox Code Playgroud)
-
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
}
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*yHK 28
从2.6版本开始,另一种方法是将字段与空数组进行比较:
ME.find({pictures: {$gt: []}})
Run Code Online (Sandbox Code Playgroud)
在shell中测试它:
> 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 ] }
Run Code Online (Sandbox Code Playgroud)
所以它正确地包含了pictures至少有一个数组元素的文档,并排除了文档,其中pictures是一个空数组,而不是数组,或者缺少.
SC1*_*000 10
ME.find({pictures: {$type: 'array', $ne: []}})
Run Code Online (Sandbox Code Playgroud)
如果使用3.2之前的 MongoDb 版本,请使用$type: 4代替$type: 'array'。请注意,此解决方案甚至不使用$size,因此索引没有问题(“查询不能对查询的 $size 部分使用索引”)
其他解决方案,包括这些(已接受的答案):
ME.find({ 图片: { $exists: true, $not: {$size: 0} } }); ME.find({ 图片: { $exists: true, $ne: [] } })
是错误的,因为它们返回文档,例如,“图片”是null、undefined、 0 等。
小智 9
db.find({ pictures: { $elemMatch: { $exists: true } } })
Run Code Online (Sandbox Code Playgroud)
$elemMatch匹配包含数组字段且至少有一个元素与指定查询匹配的文档。
因此,您将所有数组与至少一个元素相匹配。
小智 5
您可以使用以下任何一种方法来实现。
两者还注意不要为其中没有请求的键的对象返回结果:
db.video.find({pictures: {$exists: true, $gt: {$size: 0}}})
db.video.find({comments: {$exists: true, $not: {$size: 0}}})
Run Code Online (Sandbox Code Playgroud)
小智 5
使用$elemMatch运算符:根据文档
$elemMatch 运算符匹配包含数组字段的文档,该数组字段至少有一个元素与所有指定的查询条件匹配。
$elemMatches确保该值是一个数组并且不为空。所以查询会是这样的
ME.find({ pictures: { $elemMatch: {$exists: true }}})
PS 此代码的变体可以在 MongoDB 大学的 M121 课程中找到。
| 归档时间: |
|
| 查看次数: |
266601 次 |
| 最近记录: |