如何聚合/过滤不同子文档中的元素



我有一个文档如下:

{
"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可能存在于哪个元素中。在本例中,它位于contents、slides和slides.desc中,但也可能位于其他元素下。这可能吗?

谢谢!

只要条目是唯一的,您可以使用 $setUnion 操作符在现代MongoDB版本2.6及以上,以及 $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过滤掉返回的任何false值,其中"desc"字段不存在。

它产生:

{
        "_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 } }
)

与之前的输出基本相同,但当然不需要注意

结构

相关内容

  • 没有找到相关文章

最新更新