我们说我有一个帐户集合,每个帐户都有一组用户:
{
_id: 1,
users: [
{
firstName: a,
lastName: b
},
{
firstName: c,
lastName: c
}
]
}
我想查询至少有一个用户具有相同firstName
和lastName
我试着这样做:
db.accounts.find({users: {
$elemMatch: {
$where: "this.firstName == this.lastName"
}
}})
但当然因为这个错误而无法正常工作:
无法规范查询:BadValue $ elemMatch不能包含$ where表达式
我想使用find
而非aggregate
。
还有其他方法吗?
答案 0 :(得分:4)
请尝试将$where
与Array.some
一起使用,如下所示。
> db.collection.find({
$where: function() {
return this.users.some(function(obj){
return obj.firstName == obj.lastName;
})
}})
答案 1 :(得分:2)
开箱即用,但由于$where
依赖于JavaScript评估,因此使用$redact
的聚合实际上应该运行得更快,因为它使用本机运算符:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$anyElementTrue": {
"$map": {
"input": "$users",
"as": "user",
"in": { "$eq": [ "$$user.firstName", "$$user.lastName" ] }
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
因此$anyElementTrue
与$map
结合使用基本上与JavaScript .some()
相同,因为如果任何元素实际上与"firstName"
相同"lastName"
然后,这是一个true
匹配,文档是"保持"。否则它将被修剪"并丢弃。
因此,使用本机运营商的速度,我会考虑$where
以上的评估。我知道你说你不想,但你可能不认为这个说法很简单,或者比其他选择快得多。
答案 2 :(得分:0)
documentation非常清楚:
您不能将$ where表达式指定为$ elemMatch的查询条件。
你可以做的是在$where
内迭代数组:
db.collection.find(function(){
for(var i in this.users) {
if(this.users[i].firstName == this.users[i].lastName) {
return true;
}
}
})