我有一组复合键为{_id:{id:x, version:x}}
的文档:
{'_id':{'id':1, 'version':1}}
{'_id':{'id':1, 'version':2}}
{'_id':{'id':1, 'version':3}}
{'_id':{'id':2, 'version':1}}
{'_id':{'id':3, 'version':1}}
{'_id':{'id':4, 'version':1}}
{'_id':{'id':4, 'version':2}}
{'_id':{'id':4, 'version':3}}
{'_id':{'id':5, 'version':1}}
我想编写一个检索多个文档的查询,在sql中我会做类似
的操作WHERE (id,version) IN (1,1),(1,2),(3,1),(4,1)
我怎样才能在mongo中这样做?
答案 0 :(得分:1)
您实际上会使用$or
表达式。
这取决于源数据的存储方式。所以对于一组“对象”
var params = [{ id: 1, version: 1 },{ id: 2, version: 1 },{ id: 3, version: 2 }];
db.collection.find({
"$or": map.params( p =>
Object.keys(p).map( k => ({ [`_id.${k}`]: p[k] }) )
.reduce((acc,curr) => Object.assign(acc,curr), {})
)
})
或者,如果你列出了像SQL一样的“数组数组”:
var params = [[1,1],[2,1],[3,2]];
db.collection.find({
"$or": params.map(([id,version]) => ({ '_id.id': id, '_id.version': version }) )
})
这应该会让你对这里发生的转变有更多的了解。
基本上它是关于$or
和“点符号”来表示复合键。但是我在这里向你展示了一点变换,因为使用MongoDB你通常使用“数据结构”,所以你想要操纵它们而不是写出像SQL那样的语句。
没有基本上看起来像的“映射”:
db.collection.find({
"$or": [
{ "_id.id": 1, "_id.version": 1 },
{ "_id.id": 2, "_id.version": 1 },
{ "_id.id": 3, "_id.version": 2 }
]
})
这意味着所列条件中的“任何”可能与文档(或多个文档)匹配并返回它们。
所以这个例子只是JavaScript方式,因为这就是所提供的“shell”所允许的。但是你可以基本上根据你选择的语言调整方法。
当然,您首先使用以下命令在MongoDB shell中进行设置:
db.collection.insertMany([
{'_id':{'id':1, 'version':1}},
{'_id':{'id':1, 'version':2}},
{'_id':{'id':1, 'version':3}},
{'_id':{'id':2, 'version':1}},
{'_id':{'id':3, 'version':1}},
{'_id':{'id':4, 'version':1}},
{'_id':{'id':4, 'version':2}},
{'_id':{'id':4, 'version':3}},
{'_id':{'id':5, 'version':1}}
])
答案 1 :(得分:0)
基本上,我发现的是mongo没有一种有效的方法来获得具有复合索引的结果。 $或者不是高性能的,当你在法定单数> 1000时有大量的o时,似乎只是崩溃了。最后,我决定使用{' _id.id':{' $ in':[1,2,3,4 ....等等。]}}这是非常快但返回额外的文档,然后过滤掉。对于我的情况,这应该足够好,即使它不理想。
另一种方法是使用不同的索引键,它将我拥有的索引组合成64位值,其中我将前X个位分配给id,将第二个x位分配给版本。这样做可以让我快速获得我想要的确切值。 反对这种方法的主要原因是我认为在同一个碎片上保留类似的文档会是有益的,因为我可以对相同的复合索引的一部分进行分片。最后,我认为第二种方法是更好的方法。 IE,不要在mongo中使用复合索引。