【问题标题】:MongoDB - Use $where inside $elemMatchMongoDB - 在 $elemMatch 中使用 $where
【发布时间】:2016-03-22 10:36:04
【问题描述】:

假设我有一个帐户集合,每个帐户都有一组用户:

{
  _id: 1,
  users: [
    {
      firstName: a,
      lastName: b
    },
    {
      firstName: c,
      lastName: c
    }
  ]
}

我想查询至少一个用户具有相同firstNamelastName 的所有帐户

我试图做这样的事情:

db.accounts.find({users: {
    $elemMatch: {
        $where: "this.firstName == this.lastName"
    }
}})

但当然因为这个错误它没有工作:

无法规范化查询:BadValue $elemMatch 不能包含 $where 表达式

我想使用find 而不是aggregate。 还有其他方法吗?

【问题讨论】:

  • 为什么不想使用聚合?
  • @chridam 并非所有用户都有聚合查询的权限。

标签: mongodb mongodb-query


【解决方案1】:

请尝试使用$whereArray.some,如下所示。

> db.collection.find({
             $where: function() {
                  return this.users.some(function(obj){ 
                           return obj.firstName == obj.lastName;
                 })
            }})

【讨论】:

    【解决方案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() 相同,如果任何元素实际上具有与"lastName" 相同的"firstName",那么这是true匹配并且文档被“保留”。否则,它会被“修剪”并丢弃。

    因此,以本机操作员的速度,我会在 $where 评估中使用它。我知道您说您不想这样做,但您可能没有考虑到该语句比替代方案如此简单或快得多。

    【讨论】:

    • 不错的答案。我仍然需要find 的答案,但我从中学到了很多。
    • 你应该在$redactif之间使用$cond
    • @Tom 谢谢。大多数日子都发生在我身上,因为我刚开始在条件下写作。我实际上非常希望语法会变成那样而不使用$cond,因为它确实是唯一的论点。我在已经给出了适当的$where 之后写了它,因为如果你认为你仍然使用.find(),我觉得你误解了一些东西。您没有获得任何优势,实际上是在选择性能较低的选项。这些都是事实。也许您需要结合其他查询条件而您只是不知道如何?不管是什么,你都应该重新考虑。
    • 对于我自己来说,你的答案当然更好。我只需要它用于只允许使用 find() 查询的用户 - 权限问题。这就是原因
    • @Tom “权限?”我不知道这样的事情。您能否指出哪些操作限制了聚合的使用?这是actions list。我认为有人在告诉您“猪肉”,据我所知,find 的任何内容也可以执行聚合。它们只是作为 CRUD 权限。
    【解决方案3】:

    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;
            }
        }
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 1970-01-01
      • 2013-11-24
      • 2018-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多