使用不同的值更新mongoDb集合的每个文档的相同属性 [英] Update the same property of every document of a mongoDb collection with different values

查看:45
本文介绍了使用不同的值更新mongoDb集合的每个文档的相同属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a collection in mongoDb which looks like this

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

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

I am receiving a request from angularJs frontend to update this collection to

{ 
"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.请帮助我找到实现此目标的最佳方法.

I am using Mongoose 5.0 ORM with Node 6.11 and express 4.15. Please help me find the best way to achieve this.

推荐答案

您基本上想要 ,它可以获取对象的输入数组,并使用它来批量"请求更新匹配的文档.

You basically want bulkWrite(), which can take the input array of objects and use it to make a "batch" of requests to update the matched documents.

假设文档数组是在req.body.updates中发送的,那么您将遇到类似的情况

Presuming the array of documents is being sent in req.body.updates, then you would have something like

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
  })
})

在输入为以下条件的情况下发送请求:

This sends a request given the input as:

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' } } } } ]
)

通过对服务器的单个响应有效地执行所有更新.

Which efficiently performs all updates in a single request to the server with a single response.

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

Also see the core MongoDB documentation on bulkWrite(). That's the documentation for the mongo shell method, but all the options and syntax are exactly the same in most drivers and especially within all JavaScript based drivers.

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

As a full working demonstration of the method in use with mongoose:

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的更现代的环境:

Or for more modern environments with 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()
  }

})()

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

Which loads the initial data and then updates, showing the response object ( serialized ) and the resulting items in the collection after the update is processed:

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兼容

That's using syntax which is compatible with NodeJS v6.x

这篇关于使用不同的值更新mongoDb集合的每个文档的相同属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆