最近我想过滤掉MongoDB中包含某个关键字数组的记录,例如:我有五条包含关键字数组的记录:
{a:[1,2]}
{a:[1,3,8]}
{a:[1,2,5]}
{a:[3,5,1]}
{a:[4,5]}
如果我输入数组[1,2,3,5]
进行搜索,那么我想得到:
{a:[1,2]}
{a:[1,2,5]}
{a:[3,5,1]}
每个都是[1,2,3,5]
的子数组。
有什么想法吗?
请不要使用where子句(如果可能的话)。谢谢!
答案 0 :(得分:8)
在mongodb中很简单,但更难的部分是为查询准备数据。让我在奥德解释一下
简单部分
您可以使用$in
查找数组中的匹配元素。让我们试试
db.coll.find({a:{$in:[1,2,3,5]})
,结果是
{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f37c42439ed13aa728e9efc"), "a" : [ 1, 3, 8 ] }
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }
{ "_id" : ObjectId("4f37c43439ed13aa728e9efe"), "a" : [ 3, 5, 1 ] }
{ "_id" : ObjectId("4f37c43e39ed13aa728e9eff"), "a" : [ 4, 5 ] }
哦,这不是我们预期的结果。是的,因为如果发现任何匹配的元素(不一定全部),$返回一个项目。
所以我们可以通过将确切的数组元素传递给$ in来解决这个问题,例如,如果我们想找到与这些精确数组匹配的项{a:[1,2]} {a:[1,2,5] }和{a:[4,5,6]}
db.coll.find({a:{$in:[[1,2],[1,2,5],[4,5,6]]}})
你会得到
{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }
多数人
最难的部分
真正最难的部分是形成输入数组的所有可能组合[1,2,3,5]。您需要找到一种方法来获取源数组的所有组合(来自您的客户端)并将其传递给$ in。
例如,这个JS method将为您提供给定数组的所有组合
var combine = function(a) {
var fn = function(n, src, got, all) {
if (n == 0) {
if (got.length > 0) {
all[all.length] = got;
}
return;
}
for (var j = 0; j < src.length; j++) {
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
}
return;
}
var all = [];
for (var i=0; i < a.length; i++) {
fn(i, a, [], all);
}
all.push(a);
return all;
}
>> arr= combine([1,2,3,5])
会给你
[
[
1
],
[
2
],
[
3
],
[
5
],
[
1,
2
],
[
1,
3
],
[
1,
5
],
[
2,
3
],
[
2,
5
],
[
3,
5
],
[
1,
2,
3
],
[
1,
2,
5
],
[
1,
3,
5
],
[
2,
3,
5
],
[
1,
2,
3,
5
]
]
您可以将此arr
传递给$ in以查找所有macthing元素
db.coll.find({a:{$in:arr}})
会给你
{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }
等等!它仍然没有返回剩余的两个可能的项目。
因为好好看看arr,它只能找到组合。它返回[1,3,5]
但文档中的数据为[3,5,1]
。很明显$in
按给定的顺序检查项目(很奇怪!)。
所以现在你明白了比较mongodb查询真的很难!您可以更改上面的JS组合前代码,找到每个组合的可能排列,并将其传递给mongodb $in
。这就是诀窍。
由于您没有提及任何语言选择,因此难以推荐任何排列代码。但是你可以在Stackoverflow或谷歌搜索中找到很多不同的方法。
答案 1 :(得分:0)
如果我理解,您想要仅返回 属性a
的所有值的对象都在find数组参数中。
通过遵循Travis在评论中的建议,您必须遵循以下步骤:
$where
。如果将函数定义为仅用于特定属性(在本例中为a
),则可能需要跳过步骤2.但是,因为它可以是其他文档的其他属性的有用函数,我定义了一个更通用的函数,它必须保存在服务器上才能使用AFAIK(我也是Mongo的新手)。
下面是我对mongo shell的测试:
<--! language: lang-js -->
// step 1: defining the function for your specific search
only = function(property, values) {
for(var i in property) if (values.indexOf(property[i]) < 0) return false
return true
}
// step 2: saving it on the server
db.system.js.save( { _id : 'only', value : only } )
// step 3: using the function with $where
db.coll.find({$where: "only(this.a, [1,2,3,5])"})
使用您在问题上提供的5个对象,您将获得:
{ "_id" : ObjectId("4f3838f85594f902212eb532"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f3839075594f902212eb534"), "a" : [ 1, 2, 5 ] }
{ "_id" : ObjectId("4f38390e5594f902212eb535"), "a" : [ 3, 5, 1 ] }
缺点是表现。 See more.