【问题标题】:MongoDB distinct values on subdocuments子文档上的 MongoDB 不同值
【发布时间】:2015-08-04 19:20:57
【问题描述】:

我有一个有点奇怪的数据库结构如下:

我有一个具有普通属性的文档,然后我有一个元数据属性,它是一个对象数组。

metadata: {[
  {
     key: [key],
     value: [value]
  },
  ...
 ]}

编辑:永远不会有具有重复键的元数据子文档

这样做是为了保留元数据对象的顺序

现在我想使用给定键获取元数据对象的不同值。

我想使用 MongoDB 找到 [key] = "x" 的每个不同的 [value]。并在数组(不是文档)中返回不同的值

我猜这使用 distinct 命令是不可能的,但是这可以使用聚合管道还是我必须使用 Map-Reduce?

有什么建议吗?

提前致谢! :)

【问题讨论】:

    标签: mongodb mapreduce aggregation-framework distinct-values


    【解决方案1】:

    我猜你的意思是这样的:

    {
        "metadata": [
            { "key": "abc", "value": "borf" },
            { "key": "cdc", "value": "biff" }
        ]
    },
    {
        "metadata": [
            { "key": "bbc", "value": "barf" },
            { "key": "abc", "value": "borf" },
            { "key": "abc", "value": "barf" }
        ]
    }
    

    如果您过滤“abc”并获得不同的“值”条目,如下所示:

    db.collection.aggregate([
        { "$match": { "metadata.key": "abc" } },
        { "$unwind": "$metadata" },
        { "$match": { "metadata.key": "abc" } },
        { "$group": {
            "_id": "$metadata.value"
        }}
    ])
    

    甚至更好:

    db.collection.aggregate([
        { "$match": { "metadata.key": "abc" } },
        { "$redact": {
            "$cond": {
                "if": { "$eq": [ { "$ifNull": [ "$key", "abc" ] }, "abc" ] },
                "then": "$$DESCEND",
                "else": "$$PRUNE"
            }
        }},
        { "$unwind": "$metadata" },
        { "$group": {
            "_id": "$metadata.value",
            "count": { "$sum": 1 }
        }}
    ])
    

    这基本上会给:

    { "_id": "barf", "count": 1 },
    { "_id": "borf", "count": 2 }
    

    但它不可能只是“barf”和“borf”的数组。 distinct() 方法只做一个键数组,但它也非常有限。因此它只能这样做:

    db.collection.distinct("metadata.value",{ "metadata.key": "abc" })
    [ "biff", "borf", "barf" ]
    

    结果是不正确的。因此,只需从上面获取“文档”结果并应用一些“后处理”:

    db.collection.aggregate([
        { "$match": { "metadata.key": "abc" } },
        { "$redact": {
            "$cond": {
                "if": { "$eq": [ { "$ifNull": [ "$key", "abc" ] }, "abc" ] },
                "then": "$$DESCEND",
                "else": "$$PRUNE"
            }
        }},
        { "$unwind": "$metadata" },
        { "$group": {
            "_id": "$metadata.value"
        }}
    ]).map(function(doc) {
        return doc._id;
    })
    

    结果是一个仅包含不同值的普通数组:

    [ "borf", "barf" ]
    

    【讨论】:

    • 哇,感谢这个快速而深入的回答!我忘记提到的一件事是元数据子文档中永远不会有重复的键。我想我得阅读更多关于 MongoDB 文档的内容。
    • @FelixSchoeler $group 中的_id 要求所有“分组键”都减少为“唯一”值。所以不行。那里至少有一个文档链接。
    • 我的意思是源集合中的每个元数据数组,永远不会有一个对象与同一元数据数组中的另一个对象具有相同的键。所以第二个"metadata" 数组中的第二个"abc" 键永远不会出现。但是你的代码对我来说就像一个魅力:)
    • @FelixSchoeler 好吧,您应该可以看到,这里的列表中是否存在绝对没有区别。您的问题是给定键的不同值。由于缺乏示例,我编造了一些数据。但它仍然对结果没有影响,因为所有文档都是非规范化的。
    猜你喜欢
    • 2018-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 2013-05-15
    • 2021-09-10
    • 2014-06-23
    • 2021-03-19
    相关资源
    最近更新 更多