如果我的users收藏中的数据看起来像:
{ name: '...',
email: '...',
...,
photos: {
123: { url: '...', title: '...', ... },
456: { url: '...', title: '...', ... },
...
}
}
Run Code Online (Sandbox Code Playgroud)
我想找到哪个用户拥有照片ID 127,然后我使用查询:
db.users.find( {'photos.127': {'$exists' => true} } );
Run Code Online (Sandbox Code Playgroud)
我试过了,但似乎不可能让MongoDB为这个查询使用索引.我试过的索引是:db.users.ensureIndex({photos:1});.当我使用explain()mongo时告诉我它使用的是BasicCursor(即没有使用索引).
是否可以创建mongo将用于此查询的索引?
Ram*_*Vel 12
不,没有办法告诉mongodb使用索引进行存在查询.索引与数据完全相关.由于$ exists仅与密钥(字段)相关,因此无法在索引中使用.
$ exists只验证文档中是否存在给定的键(或字段).
截至 2022 年 6 月,该索引不能用于${exists: true}案例,只能部分用于其他一半案例。MongoDB 索引存在一个主要的(IMO)设计错误,人们仍然常常没有意识到,所以我发布了这个答案以及针对某些情况的解决方法。
问题是 MongoDB 将不存在的字段索引为nulls,因此null从索引的角度来看,这些字段与 s 无法区分。另外,还有一些与 JS 类比相关的混乱,其中undefined === null是 false 但却undefined == null是 true。这意味着:
{$exists: false}索引。为此,扫描索引以检索对具有 null 值和不存在值的文档的引用,获取文档,并过滤掉值等于 null 的文档。对应的 MongoDB 阶段:和。null[null, null] IXSCANFETCH with {"$not" : {$exists: true}} filter{field: null} 索引。为此,只需要索引扫描。MongoDB 将其解析为. 由于某些可能的历史原因,Mongo 还会搜索已弃用的类型/值:。IMO 将相等解释为值相等而不在结果中包含不存在的字段会更合乎逻辑。但是它就是这样啊。{field: { $eq: null }}undefined[undefined, undefined]U[null, null] IXSCANfield: {$type: "null"}. 可以使用索引。与第一种情况类似,阶段是:[null, null] IXSCAN和FETCH with {'$type': [10]} filter。不必要地获取不存在字段的文档,然后将其过滤掉。null,那么您运气不好。搜索查询是{field: {$exists: true}}. 无法使用索引。如果 mongo 使用索引,它将包含索引值,以null包含字段等于 null 的文档,以便稍后过滤掉不存在的值。因此需要全索引,因此全集合扫描效率更高。蒙戈阶段:COLLSCAN with { '$exists': true } filter.null,即可以不包含$type: null在结果中,则可以使用索引。如果您知道您的字段类型是例如 ObjectId,那么您可以搜索{field: {$type: "object"}}、类型列表:{field: {$type: ["number", "object"]}}或仅搜索{field: {$ne: "null"}}。后者将从搜索中排除null和类型。undefined蒙戈阶段是:
[{},[]) IXSCAN和FETCH'[nan.0, inf.0]U[{}, [])'和FETCH[MinKey, undefined)U(null, MaxKey] IXSCAN和FETCH。2014 年 2 月提交了一个问题:https://jira.mongodb.org/browse/SERVER-12869。不幸的是,MongoDB 还没有优先考虑它,也没有在官方文档中反映这个问题。
$ exists不会使用索引,但您可以将数据结构更改为
photos: [
{id:123, url: '...', title: '...', ... },
{id:456, url: '...', title: '...', ... },
...
]
Run Code Online (Sandbox Code Playgroud)
然后使用
db.users.ensureIndex({photos.id:1})
Run Code Online (Sandbox Code Playgroud)
为照片ID创建索引.
看来我错了,事实上,你可以强制你的$ exists查询使用你的索引.让我们继续使用上面的结构,但你的照片ID肯定不是包含在内的,也就是说有些文档会有密钥'id'而有些则不会.然后你可以在上面创建稀疏索引:
db.users.ensureIndex({'photos.id': 1}, {'sparse': true})
Run Code Online (Sandbox Code Playgroud)
然后像这样查询:
db.users.find({'photos.id': {$exists: true}}).hint({'photos.id': 1})
Run Code Online (Sandbox Code Playgroud)
您可以添加解释以查看查询是否使用索引.这是我的结果,我的收藏品的移动钥匙与你的照片类似.:
> db.test.count()
50000
> db.test.find({'mobile': {$exists: true}}).hint({'mobile': 1}).explain()
{
"cursor" : "BtreeCursor mobile_1",
"nscanned" : 49999,
"nscannedObjects" : 49999,
"n" : 49999,
"millis" : 138,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"mobile" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
> db.test.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.test",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"mobile" : 1
},
"ns" : "test.test",
"name" : "mobile_1",
"sparse" : true,
"background" : true
}
]
Run Code Online (Sandbox Code Playgroud)
希望能帮到你!
| 归档时间: |
|
| 查看次数: |
11629 次 |
| 最近记录: |