【问题标题】:mongodb - how to aggregate/filter elements in different subdocuments?mongodb - 如何聚合/过滤不同子文档中的元素?
【发布时间】:2015-09-10 08:01:59
【问题描述】:

我的文档如下所示:

{
"contents": [
    {
        "translationId": "MENU",
    },
    {
        "translationId": "PAGETITLE"
    }
],
"slides": [
    {
        "translationId": "SLIDE1",
        "imageUrl": "assets/img/room/1.jpg",
        "desc": {
            "translationId": "DESC",
        }
    },
    {
        "translationId": "SLIDE2",
        "imageUrl": "assets/img/aa/2.jpg"
    }
]}

无论数据位于哪个子文档中,我都希望根据 translationId 进行聚合。我当前的查询如下所示,它没有给我预期的结果。

db.cursor.find({"contents.translationId": { $exists: true }},
{"contents.translationId":1,'slides.translationId':1,"slides.desc.translationId":1,'_id':0})

我希望得到如下结果。有没有直接从 mongodb 查询中检索这样一个结果的好方法?

[
  {
    "translationId": "MENU"
  },
  {
    "translationId": "PAGETITLE"
  },
  {
    "translationId": "SLIDE1"
  },
  {
    "translationId": "SLIDE2"
  },
  {
    "translationId": "DESC"
  }
]

此外,我可能不知道 translationId 可能存在于哪个元素中。在这种情况下,它位于内容、幻灯片和 slides.desc 中,但它也可能位于其他一些元素下。有可能吗?

谢谢!

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    只要项目不存在,您就可以在现代 MongoDB 2.6 及更高版本中使用 $setUnion 运算符,以及使用 $map 运算符仅从另一个数组中转换所需元素:

    db.cursor.aggregate([
        { "$project": {
            "joined": { 
                "$setDifference": [
                    { "$setUnion": [
                        "$contents",
                        { "$map": {
                            "input": "$slides",
                            "as": "slide",
                            "in": {
                                "translationId": "$$slide.translationId"
                            }
                        }},
                        { "$map": {
                            "input": "$slides",
                            "as": "slide",
                            "in": {
                                "$cond": [
                                    { "$ifNull": [ "$$slide.desc.translationId", false] },
                                    { "translationId": "$$slide.desc.translationId" },
                                    false
                                ]
                            }
                        }}
                   ]},
                   [false]
                ]
            }
        }}
    ])
    

    您还需要$setDifference 过滤掉返回的任何“desc”字段不存在的false 值。

    它产生:

    {
            "_id" : ObjectId("55f13f444db9bc30de351c84"),
            "joined" : [
                    {
                            "translationId" : "DESC"
                    },
                    {
                            "translationId" : "SLIDE2"
                    },
                    {
                            "translationId" : "SLIDE1"
                    },
                    {
                            "translationId" : "PAGETITLE"
                    },
                    {
                            "translationId" : "MENU"
                    }
            ]
    }
    

    当然,如果您“根本”不知道结构,那么您需要一个带有 mapReduce 的递归函数:

    db.cursor.mapReduce(
        function() {
            var tags = [];
    
            function walkObj(obj) {
                Object.keys(obj).forEach(function(key) {
                    if ( typeof(obj[key]) == "object" ) {
                        walkObj(obj[key]);
                    } else if ( key == "translationId" ) {
                        tags.push({ "translationId": obj[key] })
                    } 
                });
            }
    
            walkObj(this);
            emit(this._id,{ "joined": tags})            
        },
        function(){},
        { "out": { "inline": 1 } }
    )
    

    它提供与以前基本相同的输出,但当然不需要了解结构

    【讨论】:

    • 我相信递归函数的方法更简单。
    • @komushi 当然,但关键是如果你对结构有“一些想法”,它不会是最“有效的”。因此,如果对象确实是随机的,并且您不可能映射所有字段位置,则您实际上应该只“走动”对象。不仅比一般的递归搜索快,而且聚合框架是本机编码运算符而不是解释的 JavaScript 代码,所以它也更快。但是使用你需要的东西来适应你的情况。
    猜你喜欢
    • 2013-06-08
    • 1970-01-01
    • 2016-08-29
    • 2016-12-19
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-17
    相关资源
    最近更新 更多