【问题标题】:MongoDB: Project using array fieldsMongoDB:使用数组字段的项目
【发布时间】:2019-07-11 16:42:54
【问题描述】:

我有一个这样的集合:每个文档都包含Message 字段,而该字段又包含Fields 的数组。 Fields 数组下的每个文档都有 ValueName 属性。

[
    {
        "_id" : ObjectId("55711efed0103b1598140076"),
        "Message" : {
            "Fields" : [ 
                {
                    "Value" : 131,
                    "Name" : "Options",
                }, 
                {
                    "Value" : 8,
                    "Name" : "Length",
                }       
            ]
        }
    },

    {
        "_id" : ObjectId("55711efed0103b1598140077"),
        "Message" : {
            "Fields" : [ 
                {
                    "Value" : 65,
                    "Name" : "Options",
                }, 
                {
                    "Value" : 13,
                    "Name" : "Length",
                },
                {
                    "Value" : 101,
                    "Name" : "Width",
                }                   
            ]
        }
    }
]

在使用db.Collection.find({}) 找到文档后,我想进行这样的投影 - 它解析Message.Fields 下的每个Field 并将它们投影到新文档中,使用Type 作为属性名称和Value 作为值。输出如下所示:

[
    {
        "_id" : ObjectId("55711efed0103b1598140076"),
        "Options" : 131,
        "Length" : 8
    },
    {
        "_id" : ObjectId("55711efed0103b1598140077"),
        "Options" : 65,
        "Length" : 13,
        "Width" : 101
    },
]

这是否可以在 MongoDB 中使用 function()aggregate 或任何其他方式来实现?

【问题讨论】:

  • 最后一个键值对中的每个对象的字段数组中都有不必要的逗号。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您可以使用aggregation$cond 运算符

db.collection.aggregate(
    [
      { $unwind: "$Message.Fields" },
      { $project: { fields: "$Message.Fields" }}, 
      { $project: 
          { 
              Option: 
                {
                  $cond: [{ $eq: [ "$fields.Name", "Options" ]}, "$fields.Value", 0 ]
                }, 
              Length: 
                {
                  $cond: [{ $eq: [ "$fields.Name", "Length" ]}, "$fields.Value", 0 ]
                }, 
              Width: 
                { 
                  $cond: [{ $eq: [ "$fields.Name", "Width" ]}, "$fields.Value", 0]
                }
          }
        }, 
        { $group: { 
                    _id: "$_id", 
                    Options: { $sum: "$Option" }, 
                    Width: { $sum: "$Width" }, 
                    Length: { $sum: "$Length" }
                  }
         } 
    ]
)

结果:

{
        "_id" : ObjectId("55711efed0103b1598140077"),
        "Options" : 65,
        "Width" : 101,
        "Length" : 13
}
{
        "_id" : ObjectId("55711efed0103b1598140076"),
        "Options" : 131,
        "Width" : 0,
        "Length" : 8
}

【讨论】:

    【解决方案2】:

    对于 MongoDB 版本 3.4.4 及更高版本,使用 $arrayToObject"$Message.Fields" 数组转换为所需的对象,但在此之前 使用上述运算符,您必须使用 $map 将数组中对象的属性重塑为键 k 和 var。这是 $arrayToObject 将列表转换为键/值对对象所必需的。

    转换对象后,您可以将其与 _id 字段合并,然后使用 $replaceRoot 将此合并文档替换为根。

    以下管道展示了这种方法:

    db.collection.aggregate([
        { "$replaceRoot": {
            "newRoot": {
                "$mergeObjects": [
                    { _id: "$_id" },
                    { "$arrayToObject": {
                        "$map": {
                            "input": "$Message.Fields",
                            "in": {
                                "k": "$$this.Name",
                                "v": "$$this.Value"
                            }
                        }
                    } }
                ]
            }
        } }
    ])
    

    使用 find() 游标中的 map() 方法,该方法将函数应用于游标访问的每个文档,并将来自后续应用程序的返回值收集到一个您可以将所需字段投影到所需结果的数组:

    var result = db.collection.find().map(function (doc){
        var obj = {};
        obj["_id"] = doc._id
        doc.Message.Fields.forEach(function (field){
            obj[field.Name] = field.Value;
        })
        return obj;
    });
    printjson(result);
    

    输出

    [
        {
            "_id" : ObjectId("55711efed0103b1598140076"),
            "Options" : 131,
            "Length" : 8
        },
        {
            "_id" : ObjectId("55711efed0103b1598140077"),
            "Options" : 65,
            "Length" : 13,
            "Width" : 101
        }
    ]
    

    【讨论】:

      【解决方案3】:

      我正在使用以下脚本使用mongo shell 生成上述结果。

      var result=[];
      
      var cursor=db.collection.find().forEach( 
      
      function(myDoc) 
      { 
          print(myDoc)
      
              var obj1={};
              obj1._id=myDoc._id;
              var len_of_fields=myDoc.Message.Fields.length;
      
              if(len_of_fields==2)
              {
                var j=0;         
                obj1.Options=myDoc.Message.Fields[j].Value;    
                obj1.Length=myDoc.Message.Fields[j+1].Value;
                result.push(obj1)  
              }
              else if(len_of_fields==3)
              {
      
                   var j=0;
                  obj1.Options=myDoc.Message.Fields[j].Value;
                  obj1.Length=myDoc.Message.Fields[j+1].Value;
                  obj1.Width=myDoc.Message.Fields[j+2].Value;
      
                    result.push(obj1)
              }   
      
          print( "DOC: ", result); 
      
      } 
      
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-10
        • 1970-01-01
        • 1970-01-01
        • 2018-05-22
        • 2015-08-09
        • 1970-01-01
        • 1970-01-01
        • 2022-07-02
        相关资源
        最近更新 更多