【问题标题】:Update in forEach on mongodb shell在 mongodb shell 上的 forEach 中更新
【发布时间】:2014-05-04 14:10:45
【问题描述】:

我有一个包含 2 条记录的集合 aTable

 {
    "title" : "record 1",
    "fields" : [ 
        {
            "_id" : 1,
            "items" : [ 
                1
            ]
        },
        {
            "_id" : 2,
            "items" : [ 
                2,3,4
            ]
        },
        {
            "_id" : 3,
            "items" : [ 
                5
            ]
        }
    ]
},

{
        "title" : "record 2",
        "fields" : [ 
            {
                "_id" : 4,
                "items" : [ 
                    7,8,9,10
                ]
            },
            {
                "_id" : 5,
                "items" : [ 

                ]
            },
            {
                "_id" : 6,
                "items" : [ 
                    11,12
                ]
            }
        ]
    }

我想从

更新字段 aTable.fields.items
items : [ 11,12 ]

items : [ 
   {item: 11, key: 0},
   {item:12, key: 0}
]

我使用 forEach 浏览字段但无法保存:

var t = db.aTable.find();

t.forEach(function( aRow ) {
    aRow.fields.forEach( function( aField ){
        aField.items.forEach( function( item ){
            var aNewItem = { item: parseInt(item), ref: 0 };
            db.aTable.update(item, {$set:aNewItem})
        } )
    } )
});

【问题讨论】:

  • 有什么错误吗?另一种选择是直接在 aRow 对象中进行更改,然后调用 db.aTable.save(aRow)
  • 因为aRow.fields是数组,所以aRow.fields中的每个元素都有mutil itemsitems 是数组。所以我们不能直接在 aRow 中更新

标签: javascript mongodb mongo-shell


【解决方案1】:

您可以直接在整个对象中进行更改,然后保存。试试下面的sn-p

db.aTable.find().forEach(function (itemWrapper){
    itemWrapper.fields.forEach(function(field){
        var items = field.items;
        var newItems = [];
        items.forEach(function(item){
          var t = {'item':item,'key':0}
          newItems.push(t);      
        })
        field.items = newItems;
    })
    db.aTable.save(itemWrapper)
})

我正在做的是遍历所有项目并使用{item : 1 , key:0} 创建一个新数组,然后将其设置回字段对象中的项目数组。

这是更新后的输出:

{
    "_id" : ObjectId("5332a192ece4ce8362c7a553"),
    "title" : "record 1",
    "fields" : [ 
        {
            "_id" : 1,
            "items" : [ 
                {
                    "item" : 1,
                    "key" : 0
                }
            ]
        }, 
        {
            "_id" : 2,
            "items" : [ 
                {
                    "item" : 2,
                    "key" : 0
                }, 
                {
                    "item" : 3,
                    "key" : 0
                }, 
                {
                    "item" : 4,
                    "key" : 0
                }
            ]
        }, 
        {
            "_id" : 3,
            "items" : [ 
                {
                    "item" : 5,
                    "key" : 0
                }
            ]
        }
    ]
}

/* 1 */
{
    "_id" : ObjectId("5332a192ece4ce8362c7a554"),
    "title" : "record 2",
    "fields" : [ 
        {
            "_id" : 4,
            "items" : [ 
                {
                    "item" : 7,
                    "key" : 0
                }, 
                {
                    "item" : 8,
                    "key" : 0
                }, 
                {
                    "item" : 9,
                    "key" : 0
                }, 
                {
                    "item" : 10,
                    "key" : 0
                }
            ]
        }, 
        {
            "_id" : 5,
            "items" : []
        }, 
        {
            "_id" : 6,
            "items" : [ 
                {
                    "item" : 11,
                    "key" : 0
                }, 
                {
                    "item" : 12,
                    "key" : 0
                }
            ]
        }
    ]
}

【讨论】:

    【解决方案2】:

    要得到你想要的,你需要一些东西:

    t.forEach(function( aRow ) {
        var newFields = [];
        aRow.fields.forEach( function( aField ){
            var newItems = [];
            aField.items.forEach( function( item ){
                var aNewItem = { item: parseInt(item), ref: 0 };
                newItems.push( aNewItem );
            } );
            newFields.push({ _id: aField._id, items: newItems });
        } )
        aTable.update(
            { _id: aRow._id }, 
            { "$set": { "fields": newFields } }
        );
    });
    

    所以基本上你需要在更新之前“重新构建”你的数组

    【讨论】:

      【解决方案3】:

      Mongo 4.2 开始,db.collection.update() 可以接受聚合管道,最后允许根据当前值更新字段,从而使用查询而不是 javascript:

      // {
      //   title: "record 1",
      //   fields: [
      //     { _id: 1, items: [1] },
      //     { _id: 2, items: [2, 3, 4] },
      //     { _id: 3, items: [5] }
      //   ]
      // }
      db.collection.update(
        {},
        [{ $set: {
             fields: { $map: {
               input: "$fields",
               as: "x",
               in: {
                 _id: "$$x._id",
                 items: { $map: {
                   input: "$$x.items",
                   as: "y",
                   in: { item: "$$y", key: 0 }
                 }}
               }
             }}
        }}],
        { multi: true }
      )
      // {
      //   title: "record 1",
      //   fields: [
      //     { _id: 1, items: [ { item: 1, key: 0 } ] },
      //     { _id: 2, items: [ { item: 2, key: 0 }, { item: 3, key: 0 }, { item: 4, key: 0 } ] },
      //     { _id: 3, items: [ { item: 5, key: 0 } ] }
      //   ]
      // }
      
      • 第一部分{} 是匹配查询,过滤要更新的文档(在本例中为所有文档)。

      • 第二部分[{ $set: { fields: { $map: { ... } } }]是更新聚合管道(注意方括号表示使用聚合管道):

        • $set 是一个新的聚合运算符,在这种情况下会替换字段的值。
        • 然后(如果我们通过样板文件)我们只是 $mapping 两个嵌套数组。
        • 更具体地说,第二个映射转换将[1, 2] 替换为[{ item: 1, key: 0 }, { item: 2, key: 0 }]
      • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-07
        • 1970-01-01
        • 2021-05-31
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-18
        相关资源
        最近更新 更多