Met à jour la même propriété de chaque document d’une collection mongoDb avec des valeurs différentes

J’ai une collection dans mongoDb qui ressemble à ceci

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

Je reçois une demande de la part de angularJs frontend pour mettre à jour cette collection.

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

J’utilise Mongoose 5.0 ORM avec Node 6.11 et Express 4.15. Aidez-moi à trouver le meilleur moyen d’y parvenir.

Vous voulez essentiellement bulkWrite() , qui peut utiliser le tableau d’objects en entrée et l’utiliser pour créer un “lot” de demandes de mise à jour des documents correspondants.

En présumant que le tableau de documents est envoyé dans req.body.updates , vous obtiendrez quelque chose comme:

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

Cela envoie une requête avec l’entrée comme:

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

Ce qui effectue efficacement toutes les mises à jour dans une seule demande au serveur avec une seule réponse.

Reportez-vous également à la documentation principale de MongoDB sur bulkWrite() . C’est la documentation de la méthode shell mongo , mais toutes les options et la syntaxe sont exactement les mêmes dans la plupart des pilotes et en particulier dans tous les pilotes JavaScript.

En tant que démonstration complète de la méthode utilisée avec la 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: Ssortingng }); const Test = mongoose.model('Test', testSchema); const log = data => console.log(JSON.ssortingngify(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()); 

Ou pour des environnements plus modernes avec 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: Ssortingng }); const Test = mongoose.model('Test', testSchema); const log = data => console.log(JSON.ssortingngify(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.ensortinges(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() } })() 

Ce qui charge les données initiales puis se met à jour, en affichant l’object de réponse (sérialisé) et les éléments résultants dans la collection après le traitement de la mise à jour:

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

Cela utilise une syntaxe compatible avec NodeJS v6.x

Un petit changement dans la réponse de Neil Lunn a fait le travail.

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

Merci à Neil Lunn.