MongoDB聚合选择性项目 [英] MongoDB aggregate selective project

查看:62
本文介绍了MongoDB聚合选择性项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在进行分组汇总时,我在重塑文档时遇到了问题.基本上,我想根据条目的类型将条目推送到字段.我的结构如下:

I am running into problems reshaping my document during aggregation for grouping. Basically I want to push entries to fields depending in their type. I have a structure as follows:

_id: P1
   entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}]
   ...

我想$ unwind和$ project这些实体,以便得到这样的结构:

I want to $unwind and $project these entities so that get a structure like:

_id: P1
   A: [X]
   B: []
_id: P1
   A: [Y]
   B: []
_id: P1
   A: []
   B: [X]

所以我可以按A或B或两者进行分组,即

so i can perform a grouping by A or B or both, i.e.

$group: {
   _id: {
       A: $A, 
       B: $B
    }
    count: {$sum : 1}

我以为我可以做到:

$unwind: $entities
$project: {
   id: §id
   A: {"$cond":[{"$eq":["$type","A"]},"$code"]}
   B: {"$cond":[{"$eq":["$type","B"]},"$code"]}
}
$group: {
  _id: "$id"
  A: {$addToSet : "$A"}
}

或类似的失败

$unwind: $entities
$group: {
  _id: "$id"
  A: {"$cond":[{"$eq":["$type","A"]},$push: "$code", null]}
  ...
}

,但是这两个版本都失败了,因为我不能做其他任何事情,而且我没有设法在条件语句中使用$ push.我得到的最接近的项目取决于类型,但是由于找不到匹配项时无法找到不向字段添加任何内容的方法,因此我得出以下结论:

but both versions fail because I cannot do nothing on else and I did not manage to use $push inside a conditional. The closest I got is project depending on the type, but since I could not find a way not to add anything to the field when there was no match, I end up with:

_id: P1
   A: [X,null,Y]
   B: [null,X,null]

弄乱了计数.我的第二个想法是过滤数组以删除null.但是我没有找到删除实体的方法,因为再次$ cond不会让我指定一个空的/不做任何事情"的情况.

which messes up the counting. My second idea was to filter the arrays to remove null. But I did not find a way to remove entities, because again $cond wouldnt let me specify an empty/"do nothing" else case.

我觉得它可以按类型和内容进行分组,并与所需的类型进行匹配,但是由于我有许多类型和任意分组,因此会形成分组树,因此这可能会变得非常复杂.对错误的想法或暗示将非常受欢迎.

I have a feeling it could work with grouping by type and content with matching of the required types, but because I have many types and arbitrary groupings resulting in a grouping tree, this might become very complicated. Ideas or hints to mistakes would be very welcome.

谢谢

编辑:基于接受的答案的解决方案

The solution based on the accepted anwser

我不得不对其稍加修改,以过滤类型所有内容均为空的情况,因为否则在匹配期间它会丢失并且因为我想保留这一知识.谢谢!

I had to slightly adapt it, to filter cases where all content of a type was null, because otherwise it would have been lost during matching and because I want to keep that knowledge. Thanks!

{$project:{
  A: {$cond: [
      {$eq: ["$A", [false]]},
      ["N/A"],
      "$A"
  ]},
  B: {$cond: [
      {$eq: ["$B", [false]]},
      ["N/A"],
      "$B"
  ]},
}},
{ "$unwind": "$A" },
{ "$match": { "A": { "$ne": false } } },
{ "$group": {
    "_id": "$_id",
    "A": { "$push": "$A" },
    "B": { "$first": "$B" }
}},
{ "$unwind": "$B" },
{ "$match": { "B": { "$ne": false } } },
{ "$group": {
    "_id": "$_id",
    "A": { "$first": "$A" },
    "B": { "$push": "$B" }
}}

推荐答案

您似乎走在正确的轨道上,有很多种方法可以从条件中删除那些false的值.您不能让它什么也不返回,但是您会摆脱不想要的值.

You seemed on the right track, there are just different approaches to removing those values of false from the conditional. You cannot have it return nothing, but you cn get rid of the values you do not want.

如果您确实想要集合"并且拥有MongoDB 2.6或更高版本,则可以使用

If you truly want "sets" and you have MongoDB 2.6 or greater available, then you basically filter out the false values using $setDifference:

db.entities.aggregate([
    { "$unwind": "$entities" },
    { "$group": {
        "_id": "$_id",
        "A": { 
            "$addToSet": {
                "$cond": [
                    { "$eq": [ "$entities.type", "A" ] },
                    "$entities.val",
                    false
                ]
            }
        },
        "B": { 
            "$addToSet": {
                "$cond": [
                    { "$eq": [ "$entities.type", "B" ] },
                    "$entities.val",
                    false
                ]
            }
        }
    }},
    { "$project": {
        "A": {
            "$setDifference": [ "$A", [false] ]
        },
        "B": {
            "$setDifference": [ "$B", [false] ]
        }
    }}
])

或者只是使用 $map $project 内的strong> 运算符:

Or just as one step using the $map operator inside $project:

db.entities.aggregate([
    {"$project": {
        "A": {
             "$setDifference": [
                 {
                     "$map": {
                         "input": "$entities",
                         "as": "el",
                         "in": {
                             "$cond": [
                                 { "$eq": [ "$$el.type", "A" ] },
                                 "$$el.val",
                                 false
                             ]
                         }
                     }
                 },
                 [false]
             ]
         },
        "B": {
             "$setDifference": [
                 {
                     "$map": {
                         "input": "$entities",
                         "as": "el",
                         "in": {
                             "$cond": [
                                 { "$eq": [ "$$el.type", "B" ] },
                                 "$$el.val",
                                 false
                             ]
                         }
                     }
                 },
                 [false]
             ]
         }
    }}
])

否则,请留在一般的 $unwind $match 运算符以过滤以下内容:

Or otherwise stay with general $unwind and $match operators to filter these:

db.entities.aggregate([
    { "$unwind": "$entities" },
    { "$group": {
        "_id": "$_id",
        "A": { 
            "$push": {
                "$cond": [
                    { "$eq": [ "$entities.type", "A" ] },
                    "$entities.val",
                    false
                ]
            }
        },
        "B": { 
            "$push": {
                "$cond": [
                    { "$eq": [ "$entities.type", "B" ] },
                    "$entities.val",
                    false
                ]
            }
        }
    }},
    { "$unwind": "$A" },
    { "$match": { "A": { "$ne": false } } },
    { "$group": {
        "_id": "$_id",
        "A": { "$push": "$A" },
        "B": { "$first": "$B" }
    }},
    { "$unwind": "$B" },
    { "$match": { "B": { "$ne": false } } },
    { "$group": {
        "_id": "$_id",
        "A": { "$first": "$A" },
        "B": { "$push": "$B" }
    }}
])

使用 $push 用于普通数组或 $addToSet 以获取唯一集合.

Using either $push for normal arrays or $addToSet for unique sets.

这篇关于MongoDB聚合选择性项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆