【问题标题】:Aggregate multiple arrays into one huge array with MongoDB使用 MongoDB 将多个数组聚合成一个巨大的数组
【发布时间】:2017-03-15 23:35:43
【问题描述】:

我收集了一个包含以下文档的集合:

{
    "_id": 0,
    "pictures": [
        {
            "path": "/path/to/first/picture.jpg",
            "web": "true"
        },
        {
            "path": "/path/to/second/picture.jpg",
            "web": "true",
        }
    ],
    "logos": [
        {
            "path": "/path/to/first/logo.jpg",
            "web": "true"
        },
        {
            "path": "/path/to/second/logo.jpg",
            "web": "false",
        }
    ]
}
{
    "_id": 1,
    "pictures": [
        {
            "path": "/a/bit/weird/path/to/picture.jpg",
            "web": "false"
        },
        {
            "path": "/another/weird/path/to/picture.jpg",
            "web": "false",
        }
    ],
    "logos": [
        {
            "path": "/path/to/another/logo.jpg",
            "web": "false"
        },
        {
            "path": "/a/last/path/to/logo.jpg",
            "web": "true",
        }
    ]
}

我想要得到的结果是符合以下条件的这个。

{ 
    "web_images": [
        {
            "path": "/path/to/first/picture.jpg",
            "web": "true"
        },
        {
            "path": "/path/to/second/picture.jpg",
            "web": "true",
        },
        {
            "path": "/path/to/first/logo.jpg",
            "web": "true"
        },
        {
            "path": "/a/last/path/to/logo.jpg",
            "web": "true",
        }
    ]
}

唯一真正的条件是获取所有路径,这些路径的“web”字段中的字符串设置为 true。 (我知道它也可能是布尔值,但在这种情况下没关系) 主要问题是将数组“logos”和“pictures”合并为一个数组。 我使用“$unwind”阅读了一些解决方案。但在这些情况下,他们试图连接一个数组。

这对我有用,但在我的真实案例中,我得到了五个包含这些对象的不同数组。他们必须把所有结果都放在一个数组中。


到目前为止,我的解决方案如下(但不起作用):
db.products.aggregate( [
    { $unwind: "$pictures" },
    { $unwind: "$logos" },
    { $group: { _id: null, pics: { $push: { $or: ["$pictures", "$logos"] } } } }
    { $project: { _id: 0, pictures: "$pics" } }
] );

如您所见,仍然缺少对“web”标志的条件检查。输出也绝对没有带来任何东西。甚至没有错误消息。


编辑

我忘记了这个问题的一个重要细节。

正如我在上半部分所述,每个文档中可以出现五个不同的数组。也有可能每个文档中都没有它们。所以它也可以是这样的:

{
    "_id": 1,
    "pictures": [
        {
            "path": "/a/bit/weird/path/to/picture.jpg",
            "web": "false"
        },
        {
            "path": "/another/weird/path/to/picture.jpg",
            "web": "false",
        }
    ]
}

这可能是我的问题与已解决的问题之间的区别,我的问题被标记为重复。正如@Styvane 告诉我的那样,它给了我大量的文件,例如:

{
    "_id" : ObjectId("57f5026aaf39013d0c9186af"),
    "web_images": null
}

我可能会因为那些缺少某些数组的文档而收到此错误。

【问题讨论】:

  • 对于条件,只需将$setUnion 表达式包装在$filter 中:db.collection.aggregate([{"$project": { "web_images": { "$filter": { "input": { "$setUnion": [ "$pictures", "$logos" ] }, "as": "p", "cond": { "$eq": [ "$$p.web", "true" ] } } } } }])
  • "$eq": [ "$$p.web", "true"] 中的 $$ 有什么作用?它对我不起作用。我只得到了数千个带有 id 和“web_images”的文档:null
  • pconcatenated 数组中每个元素的变量名。要访问 cond 表达式中的该变量,MongoDB 要求您在其前面加上 $$ 并使用“点符号”来访问子文档字段。希望我回答了你的问题。
  • 是的,谢谢你,但它仍然不想在一个文档中给我我的结果。我仍然得到大量无用的文件。 { "_id": ObjectId("someHash"), "web_images": null }
  • 糟糕,我可能忘记了一个重要细节:文档也可能不包含一个或两个字段。它可能只包含“图片”,只包含“徽标”,甚至两者都不包含。这会是个大问题吗?

标签: javascript mongodb mongodb-query aggregation-framework


【解决方案1】:

您可以使用$filter$setUnion/$concatArrays 运算符来连接和过滤您的文档。您还需要使用$ifNull 运算符将缺少的字段替换为空数组。

db.collection.aggregate([
    { "$project": { 
        "web_images": { 
            "$filter": { 
                "input": { 
                    "$setUnion": [ 
                        { "$ifNull": [ "$pictures", [] ] },
                        { "$ifNull": [ "$logos", [] ] }
                    ]
                }, 
                "as": "p", 
                "cond": { "$eq": [ "$$p.web", "true" ] } 
            } 
        } 
    }},
    { "$match": { "web_images.0": { "$exists": true } } }
])

【讨论】:

  • 非常感谢!我在“web_images”字段的管道中添加了一个 $unwind 和一个 $group。这会产生一个文档,其中每个元素都与一个数组中的条件匹配。这正是我想要的!
猜你喜欢
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
相关资源
最近更新 更多