我有下一个json。
{
"a1": {"a": "b"},
"a2": {"a": "c"}
}
我想要请求所有文件,其中a1不等于同一文件中的a2。
我怎么做?
答案 0 :(得分:73)
您可以使用$where
:
db.myCollection.find( { $where: "this.a1.a != this.a2.a" } )
但是,要注意这不会很快,因为它必须启动java脚本引擎并迭代每个文档并检查每个文档的条件。
如果您需要对大型集合执行此查询,或者经常,最好引入非正规化标记,如areEqual
。尽管如此,这种低选择性字段并不能产生良好的索引性能,因为候选集仍然很大。
答案 1 :(得分:21)
为避免JavaScript使用聚合框架:
def enqueue(elems : A*)
在我们的开发服务器上,等效的JavaScript查询需要7倍的时间才能完成。
我刚刚意识到我的回答并没有回答这个问题,这个问题想要的价值不相等(有时我真的很慢)。这将适用于此:
db.myCollection.aggregate([
{"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
{"$project": {
"a1":1,
"a2":1,
"aCmp": {"$cmp":["$a1.a","$a2.a"]}
}
},
{"$match":{"aCmp":0}}
])
如果匹配条件更改为db.myCollection.aggregate([
{"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
{"$project": {
"a1":1,
"a2":1,
"aEq": {"$eq":["$a1.a","$a2.a"]}
}
},
{"$match":{"aEq": false}}
])
,则可以使用 $ne
代替$eq
,但我发现使用true
$eq
更直观
答案 2 :(得分:6)
使用从mongo 3.6开始提供的新$expr运算符,您可以在查询查询中使用聚合表达式,如下所示:
db.myCollection.find({$expr: {$ne: ["$a1.a", "$a2.a"] } });
虽然this comment解决了这个问题,但我认为这个用例的更好匹配是使用版本3.4而不是$ project的$addFields运算符。
db.myCollection.aggregate([
{"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
{"$addFields": {
"aEq": {"$eq":["$a1.a","$a2.a"]}
}
},
{"$match":{"aEq": false}}
]);
答案 3 :(得分:4)
MongoDB在后台使用Javascript,所以
{"a": "b"} == {"a": "b"}
将是false
。
所以要比较每个你需要a1.a == a2.a
要在MongoDB中执行此操作,您将使用$ where运算符
db.myCollection.find({$where: "this.a1.a != this.a2.a"});
这假设每个嵌入式文档都有一个属性" a"。如果不是这样的话,情况会变得更复杂。
答案 4 :(得分:2)
从Mongo 4.4
开始,对于那些想要比较子文档的人,不仅要原始值(因为{"a": "b"} == {"a": "b"}
是false
),我们可以使用新的$function
聚合运算符,允许应用自定义javascript函数:
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 1, "y" : 2 } }
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }
db.collection.aggregate(
{ $match:
{ $expr:
{ $function: {
body: function(a1, a2) { return JSON.stringify(a1) != JSON.stringify(a2); },
args: ["$a1", "$a2"],
lang: "js"
}}
}
}
)
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }
$function
具有3个参数:
body
,这是要应用的函数,其参数是要比较的两个字段。args
,其中包含body
函数作为参数的记录中的字段。在我们的情况下,"$a1"
和"$a2"
都是如此。
lang
,这是编写body
函数的语言。当前仅js
可用。答案 5 :(得分:0)
感谢所有人解决我的问题-关于使用aggregate()的答案,首先让我感到困惑的一件事是,$ eq(或$ in,或许多其他运算符)根据其位置而具有不同的含义。用过的。在find()或聚合的$ match阶段,$ eq取一个值,然后选择匹配的文档:
db.items.aggregate([{$match: {_id: {$eq: ObjectId("5be5feb45da16064c88e23d4")}}}])
但是,在聚合的$ project阶段,$ eq接受2个表达式组成的数组,并创建一个值为true或false的新字段:
db.items.aggregate([{$project: {new_field: {$eq: ["$_id", "$foreignID"]}}}])
顺便说一句,这是我在项目中使用的查询,用于查找所有链接到其自身的链接项列表(由于错误)的项:
db.items.aggregate([{$project: {idIn: {$in: ["$_id","$header.links"]}, "header.links": 1}}, {$match: {idIn: true}}])