【问题标题】:Exclude fields in matching element retrieved by positional operator排除位置运算符检索到的匹配元素中的字段
【发布时间】:2014-07-28 04:13:57
【问题描述】:

我有一个 texts 集合,其中的文档如下所示:

{
    title: 'A title',
    author: 'Author Name',
    published: 1944,
    languages: [
        {
            code: 'en',
            text: 'A long english text by the author...'
        },
        {
            code: 'da',
            text: 'En lang dansk tekst skrevet af forfatteren...'
        }
        // + many more languages
    ]    
}

并且想进行查询以检索标题、作者和出版日期以及给定语言的文本,所以我这样做:

texts.findOne(
    { title: titleArg, language.code: languageArg },
    { 'title': 1, 'author': 1, 'published': 1, 'languages.$': 1 } ...

但我想返回不带 mongodb 的 _id 字段的匹配语言元素。

如果我在投影中这样做:

{ '_id': 0, 'title': 1, 'author': 1, 'published': 1, 'languages.$': 1 }

我在没有主 _id 的情况下取回文档,但如果我这样做:

{ 'languages.$._id': 0, 'title': 1, 'author': 1, 'published': 1, 'languages.$': 1 }

或者这个:

{ 'languages._id': 0, 'title': 1, 'author': 1, 'published': 1, 'languages.$': 1 }

什么都不返回。

有谁知道如何创建一个返回数组中的元素并排除该元素中的某些字段的投影?

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您似乎实际上是在说您的文档确实看起来像这样:

    {
        "_id": ObjectId("53b25ad420edfc7d0df16a0c"),
        "title": "A title",
        "author": "Author Name",
        "published": 1944,
        "languages": [
            {
                "_id": ObjectId("53b25af720edfc7d0df16a0d"),
                "code": "en",
                "text": "A long english text by the author..."
            },
            {
                "_id": ObjectId("53b25b0720edfc7d0df16a0e"),
                "code": "da",
                "text": "En lang dansk tekst skrevet af forfatteren..."
            }
        ]    
    }
    

    为了澄清这一点,MongoDB 不会在数组元素中插入 _id 值。这是某些对象文档映射器或 ODM 所做的事情,这样的 ODM 就是猫鼬。但是其他软件像 MongoDB 一样执行此操作,并且默认驱动程序仅将此字段放在集合中文档的“顶级”级别,除非在该位置指定了另一个值。

    在您希望“投影”的数组中的字段中具体或精确超出了您可以使用.find() 执行的范围。您实际上需要 .aggregate() 方法来“重塑”文档并按照您想要的方式删除所有 _id 字段:

    db.collection.aggregate([
        // Match the document(s) that meet the conditions
        { "$match": { 
            "title": "A title",
            "languages.code": "en"
        }},
    
        // Unwind the array to de-normalize for processing
        { "$unwind": "$languages" },
    
        // Match to "filter" the actual array documents
        { "$match": { "languages.code": "en" } },
    
        // Group back the array per document and keep only the wanted fields
        { "$group": {
            "_id": "$_id",
            "title": { "$first": "$title" },
            "author": { "$first": "$author" },
            "published": { "$first": "$published" },
            "languages": {
                "$push": {
                    "code": "$languages.code",
                    "text": "$languages.text"
                }
            }
        }},
    
        // Finally project to remove the "root" _id field
        { "$project": {
            "_id": 0,
            "title": 1,
            "author": 1,
            "published": 1,
            "languages": 1
        }}
    ])
    

    MongoDB 2.6 引入了一些新的运算符,使这个过程在单个 $project 阶段成为可能:

    db.collection.aggregate([
        { "$match": { 
            "title": "A title",
            "languages.code": "en"
        }},
        { "$project": {
            "_id": 0,
            "title": 1,
            "author": 1,
            "published": 1,
            "languages": {
                "$setDifference": [
                    { "$map": {
                        "input": "$languages",
                        "as": "el",
                        "in": {
                            "$cond": [
                                { "$eq": [ "$$el.code", "en" ] },
                                { "code": "$$el.code", "text": "$$el.text" },
                                false
                            ]
                        }
                    }},
                    [false]
                ]
            }
        }}
    ])
    

    此类操作的一般意图通常是比您正在执行的操作更复杂的文档重塑,包括需要匹配多个数组元素,而这是位置投影无法做到的。

    但这也是目前唯一可以按照您的意愿“更改”从数组元素中返回的字段的方法。

    另请查看aggregation operators 的完整列表,以获取对每一项的更详细说明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-01
      • 1970-01-01
      • 2012-11-28
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多