首页 文章

MongoDB按字段聚合存在

提问于
浏览
29

我很难相信这个问题还没有在某个地方被问过和回答,但是我找不到它的任何痕迹 .

我有一个需要按布尔值分组的MongoDB聚合查询:是否存在另一个字段 .

例如,让我们从这个集合开始:

> db.test.find()
{ "_id" : ObjectId("53fbede62827b89e4f86c12e"),
  "field" : ObjectId("53fbede62827b89e4f86c12d"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee002827b89e4f86c12f"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee092827b89e4f86c131"),
  "field" : ObjectId("53fbee092827b89e4f86c130"), "name" : "John" }
{ "_id" : ObjectId("53fbee122827b89e4f86c132"), "name" : "Ben" }

2个文件有“字段”,2个没有 . 注意,“field”的每个值可能不同;我们只想对它的存在进行分组(或者非null也适用于我,我没有存储任何空值) .

我已经尝试过使用$ project,但是$ exists不存在,$ cond和$ ifNull没有帮助我 . 该字段似乎总是存在,即使它不存在:

> db.test.aggregate(
  {$project:{fieldExists:{$cond:[{$eq:["$field", null]}, false, true]}}},
  {$group:{_id:"$fieldExists", count:{$sum:1}}}
)
{ "_id" : true, "count" : 4 }

我希望以下更简单的聚合工作,但由于某种原因,$ exists不支持这种方式:

> db.test.aggregate({$group:{_id:{$exists:"$field"}, count:{$sum:1}}})
assert: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed
Error: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed
    at Error (<anonymous>)
    at doassert (src/mongo/shell/assert.js:11:14)
    at Function.assert.commandWorked (src/mongo/shell/assert.js:244:5)
    at DBCollection.aggregate (src/mongo/shell/collection.js:1149:12)
    at (shell):1:9
2014-08-25T19:19:42.344-0700 Error: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed at src/mongo/shell/assert.js:13

有谁知道如何从这样的集合中获得所需的结果?

预期结果:

{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }

3 回答

  • 54

    我昨晚解决了同样的问题,这样:

    > db.test.aggregate({$group:{_id:{$gt:["$field", null]}, count:{$sum:1}}})
    { "_id" : true, "count" : 2 }
    { "_id" : false, "count" : 2 }
    

    有关其工作原理的完整说明,请参见http://docs.mongodb.org/manual/reference/bson-types/#bson-types-comparison-order .

  • 6

    $exists运算符是"query"运算符,因此它基本上用于"filter"结果而不是识别逻辑条件 .

    作为"logical"运算符,聚合框架支持$ifNull运算符 . 这将返回它存在的字段值或其未提供的备用提供值或以其他方式求值为 null

    db.test.aggregate([
        { "$group": {
            "_id": { "$ifNull": [ "$field", false ] },
            "count": { "$sum": 1 }
        }}
    ])
    

    但是,当然,即使这不是"true/false"比较,所以除非你真的想要返回它所在的字段的实际值,那么你可能最好使用$cond语句,就像你有:

    db.test.aggregate([
        { "$group": {
            "_id": { "$cond": [{ "$eq": [ "$field", null ] }, true, false ] },
            "count": { "$sum": 1 }
        }}
    ])
    

    $ifNull非常有用的地方在于替换不存在的数组字段,否则会导致使用 $unwind 的错误 . 然后,您可以执行返回单个元素或空数组的操作,这样就不会在其余的管道处理中导致问题 .

  • 5

    我通过检查未定义来解决它

    $ne : [$var_to_check, undefined]
    

    要么

    $ne:  [ { $type : "$var_to_check"}, 'missing'] }
    

    如果定义了var,则返回true

相关问题