使用不同的值更新mongoDb集合的每个文档的相同属性

时间:2018-06-09 07:03:16

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

我在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。请帮助我找到实现这一目标的最佳方法。

2 个答案:

答案 0 :(得分:4)

你基本上想要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的驱动程序中。

作为与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的更现代化的环境:

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兼容的语法

答案 1 :(得分:-1)

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

感谢Neil Lunn。