如何选择嵌入文档中的项目

时间:2014-06-04 19:34:09

标签: mongodb mongodb-query aggregation-framework pymongo

如何选择mongodb中嵌入文档中的所有项目?例如,如何选择书籍中的所有项目?

{
 "_id": 67
 "Item_1":
       {
        "books": [
            {"genre": "Classics", "author": "something"},
            {"genre": "Fiction", "author": "something"}
            {"genre": "Fiction", "author": "something"}
         ]¨
       }

}

1 个答案:

答案 0 :(得分:1)

如果您希望稍微“展平”您的架构,那么您可以使用聚合框架并使用$project管道运算符来执行此操作。这比.find()可用的投影还要多一些功能,在此示例中,您还使用$unwind将数组“反规范化”为文档:

db.collection.aggregate([
    { "$unwind": "$Item_1.books" },
    { "$project": {
        "genre": "$Item_1.books.genre", "author": "$Item_1.books.author"
    }}
])

这会给你一个像这样的结果:

{ "_id": 67, "genre": "Classics", "author": "something" },
{ "_id": 67, "genre": "Fiction", "author": "something" }
{ "_id": 67, "genre": "Fiction", "author": "something" }

保留引用原始文档的内容确实有一定意义,除非您将其排除,否则_id将会存在。但如果你真的想要,你可以随时排除。

此外,您可以过滤此列表以获得多个结果,例如只是为了获得“小说”类型:

db.collection.aggregate([
    { "$unwind": "$Item_1.books" },
    { "$match": { "Item_1.books.genre": "Fiction" } }
    { "$project": {
        "genre": "$Item_1.books.genre", "author": "$Item_1.books.author"
    }}
])

给你:

{ "_id": 67, "genre": "Fiction", "author": "something" }
{ "_id": 67, "genre": "Fiction", "author": "something" }

在多个文档中,在管道中首先使用额外的$match也是有意义的,以减少其数组中不包含“Fiction”类型的文档数量。

MongoDB 2.6的另一种形式也可能是这样做:

db.collection.aggregate([
    { "$match": { "Item_1.books.genre": "Fiction" } },
    { "$project": {
        "books": {
            "$setDifference: [
                { "$map": {
                    "input ": "$Item_1.books",
                    "as": "el",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.genre", "Fiction" ] },
                            "$$el",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    { "$unwind": "$books" },
    { "$project": {
        "genre": "$books.genre",
        "author": "$books.fiction"
    }}
])

这会将数组元素上的$match移动到“内联”版本,以使用$map$setDifference过滤数组的内容。这只是另一种方法,并且考虑到阵列的大小,实用程序可能会有所不同,其中小尺寸将产生很小的差异。

作为最后一点,您的架构似乎被锁定在那个“Item_1”键作为对象。如果你的实际意图是拥有其中许多并确实在它们之间搜索或组合结果,那么架构更改将极大地有利于你查询:

{
    "_id": 67
    "books": [
        {"type": "Item1", "genre": "Classics", "author": "something"},
        {"type": "Item1", "genre": "Fiction", "author": "something"},
        {"type": "Item1", "genre": "Fiction", "author": "something"},
        {"type": "Item2", "genre": "Fiction", "author": "something"}
    ]¨

}

这样可以轻松地在各种键之间进行组合,或者实际上可以分开或组合,而无需像现在一样直接指定字段的路径。