Javascript 查找数组中某个字段与另一个字段进行比较的文档
假设我有一个文档集,看起来像这样:Javascript 查找数组中某个字段与另一个字段进行比较的文档,javascript,mongodb,mongodb-query,aggregation-framework,Javascript,Mongodb,Mongodb Query,Aggregation Framework,假设我有一个文档集,看起来像这样: { "_id" : ObjectId("5afa6df3a24cdb1652632ef5"), "createdBy" : { "_id" : "59232a1a41aa651ddff0939f" }, "owner" : { "_id" : "5abc4dc0f47f732c96d84aac" }, "acl" : [ { "profile
{
"_id" : ObjectId("5afa6df3a24cdb1652632ef5"),
"createdBy" : {
"_id" : "59232a1a41aa651ddff0939f"
},
"owner" : {
"_id" : "5abc4dc0f47f732c96d84aac"
},
"acl" : [
{
"profile" : {
"_id" : "59232a1a41aa651ddff0939f"
}
},
{
"profile" : {
"_id" : "5abc4dc0f47f732c96d84aac"
}
}
]
}
我想找到createdBy.\u id!=所有者。_id
,其中createdBy。_id
出现在acl
数组中的一个条目中。最后,我将要更新所有这些文档,以将owner.\u id
字段设置为等于createdBy.\u id
字段。现在,我只是想弄清楚如何查询要更新的文档子集
到目前为止,我已经得出了以下结论:
db.boards.find({
$where: "this.createdBy._id != this.owner._id",
$where: function() {
return this.acl.some(
function(e) => {
e.profile._id === this.createdBy._id
}, this);
}
)
(我使用了ES5语法以防ES6不正常)
但当我运行此查询时,我得到以下错误:
错误:错误:{“确定”:0,“errmsg”:“类型错误:e.profile为”
未定义:\n_funcs2/您仍然可以在MongoDB 3.2中使用
aggregate()
,但只需使用:
或者对于MongoDB 3.2 shell,您只需要保留此的一个作用域副本,您的语法有点不正确:
db.boards.find({
"$where": function() {
var self = this;
return (this.createdBy._id != this.owner._id)
&& this.acl.some(function(e) {
return e.profile._id === self.createdBy._id
})
}
})
或者在ES6兼容的环境中,然后:
db.boards.find({
"$where": function() {
return (this.createdBy._id != this.owner._id)
&& this.acl.some(e => e.profile._id === this.createdBy._id)
}
})
聚合是这两种方法中性能最好的一种,应该总是比使用JavaScript评估更好
值得一提的是,新的语法应该是:
db.boards.find({
"$expr": {
"$and": [
{ "$ne": [ "$createdBy._id", "$owner._id" ] },
{ "$in": [ "$createdBy._id", "$acl.profile._id"] }
]
}
})
优先于语法稍短的地方使用
注意此处JavaScript比较有效的唯一原因是您错误地将
ObjectId
值存储为这些字段中的“字符串”。如果存在与\u id
字段类似的“real”ObjectId
,则比较需要从valueOf()中获取“字符串”
为了比较:
没有这一点,它实际上是一个与JavaScript的“对象比较”,而{a:1}==={a:1}
实际上是false
。因此,避免这种复杂性是另一个原因,而不是有本机操作符
@Ashish他们经常这样做,因为我主要是在这里键入他们,这是在早餐时完成的。更正了命名和缺少括号。嗨,尼尔,谢谢你的回答,尽管我需要更多的帮助。关于第一个查询(使用
aggregate()
),我看到它返回的结果是所有者。\u id
=createdBy.\u id
,这是我不想看到的。我还想更新所有生成的文档以设置所有者。\u id
等于createdBy.\u id
(我将编辑我的问题以包括这一点)。我不确定是否可以执行updateMany()
使用聚合。关于接下来的两个(javascript)查询,我仍然会收到关于“e.profile未定义”的相同错误消息@Kevin这里没有一个示例返回这两个字段匹配的位置,因为它们都有一个明确的条件,表示它们不应该匹配。如果您看到不同的结果,则可能会有一个一串"在一个字段中,在另一个字段中使用ObjectId
。解决这是一个不同的问题。您可以在可用的情况下使用$expr
或$where
进行更新,我已通过复制问题中提供的数据和我的代码来运行查询,一切正常。如果您正在执行不同的操作,请不要执行,我建议gest您也可以从这里复制文档并从这里运行查询。@Kevin,因为实际上“没有错误”通过这里的查询,它按照问题中提供的实际数据的设计工作,那么你就有了一种方法来确认这一点并继续前进,如果你有新的问题的话。但是这里提出的问题已经得到了充分的回答。事实上,你已经得到了一个详细的“注释”在ObjectId
上,您的错误似乎很明显。因此,发生TypeError的原因是,某些文档的acl
数组元素没有profile
字段。这是我的疏忽,因为我对该集合的架构做出了错误的假设。我将添加关于t这一点。谢谢。您认为提供的答案中是否有某些内容不能解决您的问题?如果是,请对答案进行评论,以澄清哪些内容确实需要解决,哪些问题没有解决。如果它确实回答了您提出的问题,请注意您提出的问题
db.boards.find({
"$where": function() {
return (this.createdBy._id != this.owner._id)
&& this.acl.some(e => e.profile._id === this.createdBy._id)
}
})
db.boards.find({
"$expr": {
"$and": [
{ "$ne": [ "$createdBy._id", "$owner._id" ] },
{ "$in": [ "$createdBy._id", "$acl.profile._id"] }
]
}
})
return (this.createdBy._id.valueOf() != this.owner._id.valueOf())
&& this.acl.some(e => e.profile._id.valueOf() === this.createdBy._id.valueOf())