MongoDB:如何将$ size的数组与另一个文档项进行比较?

时间:2014-03-30 17:44:11

标签: javascript node.js mongodb mongodb-query aggregation-framework

MongoDB:如何在mongo控制台和JavaScript中使用Node.js这样做:

db.turnys.find( { users:{$size:seats } } )

turnydb.turnys看起来像这样:

[
  {
    "gId": "5335e4a7b8cf51bcd054b423",
    "seats": 2,
    "start": "2014-03-30T14:23:29.688Z",
    "end": "2014-03-30T14:25:29.688Z",
    "rMin": 800,
    "rMax": 900,
    "users": [],
    "_id": "533828e1d1a483b7fd8a707a"
  },
  {
    "gId": "5335e4a7b8cf51bcd054b423",
    "seats": 2,
    "start": "2014-03-30T14:23:29.688Z",
    "end": "2014-03-30T14:25:29.688Z",
    "rMin": 900,
    "rMax": 1000,
    "users": [],
    "_id": "533828e1d1a483b7fd8a707b"
  },
...
]

5 个答案:

答案 0 :(得分:2)

虽然您可以按照其他人的建议使用$where进行跨领域比较,但如果可能的话,我不建议使用它:

此搜索无法使用任何索引。 Mongo将扫描每个文档并对每个文档执行JavaScript表达式以进行跨字段比较。这将是一个昂贵且缓慢的操作。

进入下一版本的MongoDB(2.6),您将能够在聚合中使用$size operator,这可以比较两个字段。

但是,为了获得最佳性能,我建议您存储一个物化布尔值,用于存储users数组中元素的数量是否等于seats中存储的数量。如果您不想获取整个数组以获取计数并与字段“席位”进行比较,则可以使用$inc(正数和负数)轻松存储当前用户的数量。

如果您必须使用$where,我建议您尝试进行一些过滤,以避免全表扫描。可能是日期范围,或者检查users数组是否为空,等等。

答案 1 :(得分:1)

您可以使用$where查询:

db.turnys.find({ $where: "this.users.length == this.seats" })

答案 2 :(得分:1)

您可以将$where运算符与包含JS表达式的String或直接使用JavaScript函数一起使用:

> db.turnys.find(function() { return this.users.length == this.seats })

答案 3 :(得分:1)

您可以使用以下任何一种方法

db.flight.find({"$where":"function() { return this.users.length == this.seats}" })

db.turnys.find({ $where: "this.users.length == this.seats" })

db.turnys.find(function() { return this.users.length == this.seats })

这些都将满足您的目的,但事情是效率,除非必要,否则不应使用“$ where”查询:它们比常规查询慢得多,因此请尝试避免使用“$ where”进行查询。

答案 4 :(得分:1)

接受以任何方式使用$where运算符时存在真正的问题。特别是考虑到你提出的一些“后期”问题。您需要 阅读此运营商的手册页(如链接中所示)。

短点:

  • $where运算符调用完整集合扫描以进行比较。这是“真实世界”案例中的错误新闻,因为无法“约束”此搜索以任何方式使用索引,从而减少工作集。

  • 本质上,此运算符调用“任意JavaScript执行”。这意味着两件事。 1 。)每个文档必须从其本机BSON表单扩展为“JavaScript”对象表单(成本),以进行每次比较。 2 。)您正在调用“JavaScript”解释器,即本机代码,每个每次比较。

    < / LI>

One的答案为您提供了有效警告,但它没有为您提供实际答案。所以这就是:

如上所述, 应该实际上保留文档中“数组”元素的“计数”,如果这对您很重要的话。但是,虽然您可能已将此视为有效,但正确比较完成如下。

因此,我们假设您确实按照建议使用$inc,以便在文档中保留total_users字段。

db.collection.aggregate([
    { "$project": {
        "gId": 1,
        "alloc": { "$eq": [ "$total_users", "$seats" ] }
    }},
    { "$match": { "alloc": 1 } }
])

其中基本上你可以$project文档中你想要的所有字段,只要你通过“alloc”字段进行比较,只需做一个“逻辑” “与$eq运算符一起显示的比较。

在将来的版本中(编写后不久),您甚至可以在“聚合”操作中找到数组的$size。所以“而不是”在“数组”成员上保留一个计数器,你可以这样做:

db.collection.aggregate([
    { "$project": {
        "gId": 1,
        "alloc": { "$eq": [ { "$size": "$users" }, "$seats" ] }
    }},
    { "$match": { "alloc": 1 } }
])

但自然会带来“成本”,所以仍然最好的选择是根据您的需要在文档上保留“反击”。

虽然两个接近这里*仍然**导致“集合扫描”(在此上下文中,因为没有其他$匹配条件),最终结果比其他答案中显示的“JavaScript”执行速度倍。

使用“本机代码”方法作为最佳实践解决方案。