MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Aktualisieren Sie dieselbe Eigenschaft jedes Dokuments einer mongoDb-Sammlung mit unterschiedlichen Werten

Sie möchten im Grunde bulkWrite() , das das Eingabearray von Objekten nehmen und es verwenden kann, um einen "Batch" von Anfragen zu erstellen, um die übereinstimmenden Dokumente zu aktualisieren.

Angenommen, das Array von Dokumenten wird in req.body.updates gesendet , dann hätten Sie so etwas wie

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

Dies sendet eine Anfrage mit der Eingabe als:

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

Dadurch werden alle Aktualisierungen in einer einzigen Anfrage an den Server mit einer einzigen Antwort effizient durchgeführt.

Siehe auch die MongoDB-Kerndokumentation unter bulkWrite() . Das ist die Dokumentation für mongo Shell-Methode, aber alle Optionen und Syntax sind in den meisten Treibern und insbesondere in allen JavaScript-basierten Treibern genau gleich.

Als voll funktionsfähige Demonstration der bei Mungo verwendeten Methode:

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

Oder für modernere Umgebungen mit 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()
  }

})()

Die die anfänglichen Daten lädt und dann aktualisiert und das Antwortobjekt ( serialisiert ) und die resultierenden Elemente in der Sammlung anzeigt, nachdem die Aktualisierung verarbeitet wurde:

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

Das verwendet eine Syntax, die mit NodeJS v6.x kompatibel ist