我正在为我们的客户估算MongoDB。根据我们的要求,我们需要与一些实体ent
变量名称 - 值对组合。
db.ent.insert({'a':5775, 'b':'b1'})
db.ent.insert({'c':'its a c', 'b':'b2'})
db.ent.insert({'a':7557, 'c':'its a c'})
在此之后,我需要密切查询ent
是否存在字段:
db.ent.find({'a':{$exists:true}})
db.ent.find({'c':{$exists:false}})
Per MongoDB docs:
$存在即使使用索引也不是很有效,尤其是。使用{$ exists:true},因为它实际上必须扫描所有索引值。
那里的专家可以提供更有效的方式(即使转换范式)快速处理不同的名称 - 值对
答案 0 :(得分:9)
您可以像这样重新设计架构:
{
pairs:[
{k: "a", v: 5775},
{k: "b", v: "b1"},
]
}
然后你索引你的密钥:
db.people.ensureIndex({"pairs.k" : 1})
在此之后,您将能够按完全匹配进行搜索:
db.ent.find({'pairs.k':"a"})
如果您使用由@WesFreeman提议的稀疏索引和当前架构,则需要在要搜索的每个键上创建索引。它可能会影响写入性能,或者如果您的密钥不是静态的,则无法接受。
答案 1 :(得分:2)
只需重新设计您的架构,使其成为可索引的查询。您的用例实际上类似于MongoDB The Definitive Guide中给出的第一个示例应用程序。
如果您希望/需要result.a
方便,只需将密钥存储在可转位的地方。
而不是现有的:
db.ent.insert({a:5775, b:'b1'})
DO
db.ent.insert({a:5775, b:'b1', index: ['a', 'b']})
那是一个可索引的查询:
db.end.find({index: "a"}).explain()
{
"cursor" : "BtreeCursor index_1",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"index" : [
[
"a",
"a"
]
]
}
}
或者您是否有可能通过值查询:
db.ent.insert({
a:5775,
b:'b1',
index: [
{name: 'a', value: 5775},
{name: 'b', value: 'b1'}
]
})
这也是一个可索引的查询:
db.end.find({"index.name": "a"}).explain()
{
"cursor" : "BtreeCursor index.name_",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"index.name" : [
[
"a",
"a"
]
]
}
}
答案 2 :(得分:1)
我认为稀疏索引就是答案,尽管每个字段都需要一个索引。 http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes
稀疏索引应该有助于$ exists:true查询。
即使如此,如果你的领域不是很稀疏(意味着它主要是设置的),它对你的帮助也不大。
更新我想我错了。看起来有一个开放的问题(https://jira.mongodb.org/browse/SERVER-4187)仍然存在$ exists不使用稀疏索引。但是,您可以使用find和sort执行类似这样的操作,看起来它正确使用了稀疏索引:
db.ent.find({}).sort({a:1});
以下是使用示例值完整演示的差异:
> db.ent.insert({'a':5775, 'b':'b1'})
> db.ent.insert({'c':'its a c', 'b':'b2'})
> db.ent.insert({'a':7557, 'c':'its a c'})
> db.ent.ensureIndex({a:1},{sparse:true});
请注意find({}).sort({a:1})
使用索引(BtreeCursor):
> db.ent.find({}).sort({a:1}).explain();
{
"cursor" : "BtreeCursor a_1",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
find({a:{$exists:true}})
进行全面扫描:
> db.ent.find({a:{$exists:true}}).explain();
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
看起来你也可以使用.hint({a:1})强制它使用索引。
> db.ent.find().hint({a:1}).explain();
{
"cursor" : "BtreeCursor a_1",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
答案 3 :(得分:0)
如何将不存在字段设置为null
?然后,您可以使用{field: {$ne: null}}
查询它们。
db.ent.insert({'a':5775, 'b':'b1', 'c': null})
db.ent.insert({'a': null, 'b':'b2', 'c':'its a c'})
db.ent.insert({'a':7557, 'b': null, 'c':'its a c'})
db.ent.ensureIndex({"a" : 1})
db.ent.ensureIndex({"b" : 1})
db.ent.ensureIndex({"c" : 1})
db.ent.find({'a':{$ne: null}}).explain()
这是输出:
{
"cursor" : "BtreeCursor a_1 multi",
"isMultiKey" : false,
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 5,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 5,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
null
],
[
null,
{
"$maxElement" : 1
}
]
]
},
"server" : "my-laptop"
}