【问题标题】:mongo db aggregation/mapreducemongodb聚合/mapreduce
【发布时间】:2015-10-12 13:58:58
【问题描述】:

我正在尝试从我的 mongo-documents 对象中提取 uniq 键 + 所有 uniq 值。

假设我的文档结构如下:

{
    "userId": "1234",
    "formFields": {
        "field1": "value1",
        "field2": "value2"
    }
},
{
    "userId": "1234",
    "formFields": {
        "field3": "value3",
        "field1": "value1-edited"
    }
},
{
    "userId": "1234",
    "formFields": {
        "field3": "value3",
        "field1": "value1-edited"
    }
}

我想聚合来自用户“1234”的所有文档以获得“formFields”的不同值

结果应该是这样的:

{
    "_id": "1234",
    "formFields": {
        "field1": [
            "value1",
            "value1-edited"
        ],
        "field2": [
            "value2"
        ],
        "field3": [
            "field3"
        ],
        "field4": [
            "field4"
        ]
    }
}

formFields 中的键是动态的。 我尝试使用聚合和 mapreduce 来解决问题,但没有找到任何可以用作基础的工作示例。

谁能回答这个问题?

谢谢

问候 头盔

【问题讨论】:

  • 你用聚合框架尝试了什么代码?
  • 我只是想找到一个好的样本来开始一个,其中一些在这里:gist.github.com/hjanuschka/6fe70ca46c8b681a48d8 实际上我在零点 - 刚开始使用 mongodb - 我不知道去哪里有这个要求。

标签: mongodb mongodb-query


【解决方案1】:

由于您有事先不知道的动态键,因此您需要获取这些字段的列表,以便在聚合管道中使用它们。获取该列表的一种方法是通过 mapReduce。下面演示了这种方法。在 Map-Reduce 操作中,formFields 子文档中的键数组生成到输出集合“uploads_keys”,然后用于生成聚合管道表达式:

var mr = db.runCommand({
    "mapreduce" : "uploads",
    "map" : function() {
        for (var key in this.formFields) { emit(key, null); }
    },
    "reduce" : function(key, stuff) { 
        return null  
    }, 
    "out": "uploads" + "_keys"
});

var groupKeys = {},
    projectKeys = { "formFields": {} };
db[mr.result].distinct("_id").forEach(function (key){    
    groupKeys[key] = { "$push": "$formFields." + key };
    projectKeys["formFields"][key] = "$" + key
});

groupKeys["_id"] = "$userId";

> printjson(groupKeys);
{
        "field1" : {
                "$push" : "$formFields.field1"
        },
        "field2" : {
                "$push" : "$formFields.field2"
        },
        "field3" : {
                "$push" : "$formFields.field3"
        },
        "_id" : "$userId"
}
> printjson(projectKeys);
{
        "formFields" : {
                "field1" : "$field1",
                "field2" : "$field2",
                "field3" : "$field3"
        }
}

然后您可以在聚合管道中使用这些变量:

db.uploads.aggregate([
    { "$group": groupKeys },
    { "$project": projectKeys }
])

【讨论】:

  • 好的,这实际上是一个很好的起点——做我想做的事!但是:它们的键是硬编码的——这块有动态键的变体吗? - 并且 $push 似乎不是唯一的
  • 我已经用一种方法更新了我的答案,您可以采用这种方法来生成动态键列表。
  • 这就像我正在寻找的 99.9% 的解决方案 - 非常感谢 - 有机会踢出重复值吗?
  • 是的,确实很有可能。只需在 $group 管道中使用 $addToSet 代替 $push 运算符即可。另外,如果您能阅读What should I do when someone answers my question?,那将非常有帮助
  • THX - addToSet 做到了!现在它是 100% 完美的 - 很多谢谢,我已经确认了你的问题,只是想等待我得到 uniqe 问题的回复。
猜你喜欢
  • 2012-12-12
  • 2023-03-07
  • 2016-03-08
  • 1970-01-01
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多