【问题标题】:Update the same property of every document of a mongoDb collection with different values使用不同的值更新 mongoDb 集合的每个文档的相同属性
【发布时间】:2018-11-19 04:07:00
【问题描述】:

我在 mongoDb 中有一个集合,看起来像这样

{ 
"slno" : NumberInt(1),
"name" : "Item 1"
} 
{ 
"slno" : NumberInt(2),
"name" : "Item 2"
} 
{ 
"slno" : NumberInt(3),
"name" : "Item 3"
} 

我收到来自 angularJs 前端的请求,要求将此集合更新为

{ 
"slno" : NumberInt(1),
"name" : "Item 3"
} 
{ 
"slno" : NumberInt(2),
"name" : "Item 1"
} 
{ 
"slno" : NumberInt(3),
"name" : "Item 2"
} 

我正在使用 Mongoose 5.0 ORM 和 Node 6.11 并表达 4.15。请帮助我找到实现这一目标的最佳方法。

【问题讨论】:

    标签: node.js mongodb express mongoose mean-stack


    【解决方案1】:

    您基本上想要bulkWrite(),它可以获取对象的输入数组并使用它来发出“批量”请求以更新匹配的文档。

    假设文档数组是在req.body.updates 中发送的,那么你会得到类似的东西

    const Model = require('../models/model');
    
    router.post('/update', (req,res) => {
      Model.bulkWrite(
        req.body.updates.map(({ slno, name }) => 
          ({
            updateOne: {
              filter: { slno },
              update: { $set: { name } }
            }
          })
        )
      })
      .then(result => {
        // maybe do something with the WriteResult
        res.send("ok"); // or whatever response
      })
      .catch(e => {
        // do something with any error
      })
    })
    

    这会根据输入发送一个请求:

    bulkWrite([
       { updateOne: { filter: { slno: 1 }, update: { '$set': { name: 'Item 3' } } } },
       { updateOne: { filter: { slno: 2 }, update: { '$set': { name: 'Item 1' } } } },
       { updateOne: { filter: { slno: 3 }, update: { '$set': { name: 'Item 2' } } } } ]
    )
    

    在对服务器的单个请求中通过单个响应有效地执行所有更新。

    另请参阅bulkWrite() 上的核心 MongoDB 文档。这是mongo shell 方法的文档,但所有选项和语法在大多数驱动程序中都完全相同,尤其是在所有基于 JavaScript 的驱动程序中。

    作为与猫鼬一起使用的方法的完整工作演示:

    const { Schema } = mongoose = require('mongoose');
    
    const uri = 'mongodb://localhost/test';
    
    mongoose.Promise = global.Promise;
    mongoose.set('debug',true);
    
    const testSchema = new Schema({
      slno: Number,
      name: String
    });
    
    const Test = mongoose.model('Test', testSchema);
    
    const log = data => console.log(JSON.stringify(data, undefined, 2));
    
    const data = [1,2,3].map(n => ({ slno: n, name: `Item ${n}` }));
    
    const request = [[1,3],[2,1],[3,2]]
      .map(([slno, n]) => ({ slno, name: `Item ${n}` }));
    
    mongoose.connect(uri)
      .then(conn =>
        Promise.all(Object.keys(conn.models).map( k => conn.models[k].remove()))
      )
      .then(() => Test.insertMany(data))
      .then(() => Test.bulkWrite(
        request.map(({ slno, name }) =>
          ({ updateOne: { filter: { slno }, update: { $set: { name } } } })
        )
      ))
      .then(result => log(result))
      .then(() => Test.find())
      .then(data => log(data))
      .catch(e => console.error(e))
      .then(() => mongoose.disconnect());
    

    或者对于更现代的环境使用async/await

    const { Schema } = mongoose = require('mongoose');
    
    const uri = 'mongodb://localhost/test';
    
    mongoose.Promise = global.Promise;
    mongoose.set('debug',true);
    
    const testSchema = new Schema({
      slno: Number,
      name: String
    });
    
    const Test = mongoose.model('Test', testSchema);
    
    const log = data => console.log(JSON.stringify(data, undefined, 2));
    
    const data = [1,2,3].map(n => ({ slno: n, name: `Item ${n}` }));
    
    const request = [[1,3],[2,1],[3,2]]
      .map(([slno,n]) => ({ slno, name: `Item ${n}` }));
    
    (async function() {
    
      try {
    
        const conn = await mongoose.connect(uri)
    
        await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));
    
        await Test.insertMany(data);
        let result = await Test.bulkWrite(
          request.map(({ slno, name }) =>
            ({ updateOne: { filter: { slno }, update: { $set: { name } } } })
          )
        );
        log(result);
    
        let current = await Test.find();
        log(current);
    
        mongoose.disconnect();
    
      } catch(e) {
        console.error(e)
      } finally {
        process.exit()
      }
    
    })()
    

    加载初始数据然后更新,显示响应对象(序列化)和处理更新后集合中的结果项:

    Mongoose: tests.remove({}, {})
    Mongoose: tests.insertMany([ { _id: 5b1b89348f3c9e1cdb500699, slno: 1, name: 'Item 1', __v: 0 }, { _id: 5b1b89348f3c9e1cdb50069a, slno: 2, name: 'Item 2', __v: 0 }, { _id: 5b1b89348f3c9e1cdb50069b, slno: 3, name: 'Item 3', __v: 0 } ], {})
    Mongoose: tests.bulkWrite([ { updateOne: { filter: { slno: 1 }, update: { '$set': { name: 'Item 3' } } } }, { updateOne: { filter: { slno: 2 }, update: { '$set': { name: 'Item 1' } } } }, { updateOne: { filter: { slno: 3 }, update: { '$set': { name: 'Item 2' } } } } ], {})
    {
      "ok": 1,
      "writeErrors": [],
      "writeConcernErrors": [],
      "insertedIds": [],
      "nInserted": 0,
      "nUpserted": 0,
      "nMatched": 3,
      "nModified": 3,
      "nRemoved": 0,
      "upserted": [],
      "lastOp": {
        "ts": "6564991738253934601",
        "t": 20
      }
    }
    Mongoose: tests.find({}, { fields: {} })
    [
      {
        "_id": "5b1b89348f3c9e1cdb500699",
        "slno": 1,
        "name": "Item 3",
        "__v": 0
      },
      {
        "_id": "5b1b89348f3c9e1cdb50069a",
        "slno": 2,
        "name": "Item 1",
        "__v": 0
      },
      {
        "_id": "5b1b89348f3c9e1cdb50069b",
        "slno": 3,
        "name": "Item 2",
        "__v": 0
      }
    ]
    

    这是使用与 NodeJS v6.x 兼容的语法

    【讨论】:

    • 感谢@Neil Lunn 的帮助。
    【解决方案2】:

    Neil Lunn 的回答稍作改动就完成了任务。

    const Model = require('../models/model');
    
    router.post('/update', (req,res) => {
    
    var tempArray=[];
    
    req.body.updates.map(({slno,name}) => {
        tempArray.push({
          updateOne: {
            filter: {slno},
            update: {$set: {name}}
          }
        });
     });
    
    Model.bulkWrite(tempArray).then((result) => {
      //Send resposne
    }).catch((err) => {
       // Handle error
    });
    

    感谢尼尔·伦恩。

    【讨论】:

    • 只是小费。我认为至少有一个人不喜欢这个答案,因为Array.map() 已经返回了一个数组,所以不需要Array.push() 到另一个数组。我还为您提供了工作代码示例并显示了运行该代码的输出,因此应该很清楚没有必要“更改”任何东西以使其工作。如果您花时间了解这些方法,我可能会帮助您编写更好的代码。
    • 我明白了。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 2015-06-25
    • 2020-10-02
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    相关资源
    最近更新 更多