sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongoose skriver över dokumentet snarare än `$set`-fält

Faktiskt, men för det faktum att mongoose faktiskt "bråkar med" uppdateringen under täcket, är detta faktiskt standardåtgärden för din inlämning till en vanlig MongoDB-funktion.

Så mongoose anser att det är "klokt" som en bekvämlighetsmetod att "förutsätta" att du menade att utfärda en $set instruktion här. Eftersom du faktiskt inte vill göra det i det här fallet stänger du av det beteendet via { overwrite: true } i alternativen som skickas till någon .update() metod:

Som ett fullständigt exempel:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const testSchema = new Schema({
  name: String,
  phone: String
});

const Test = mongoose.model('Test', testSchema);

function log(data) {
  console.log(JSON.stringify(data,undefined,2))
}

(async function() {

  try {

    const conn = await mongoose.connect(uri,options);

    // Clean data
    await Promise.all(
      Object.keys(conn.models).map( m => conn.models[m].remove({}) )
    );

    // Create a document
    let test = await Test.create({
      name: 'john doe',
      phone: '+12345678901'
    });
    log(test);

    // This update will apply using $set for the name
    let notover = await Test.findOneAndUpdate(
      { _id: test._id },
      { name: 'Bill S. Preston' },
      { new: true }
    );
    log(notover);

    // This update will just use the supplied object, and overwrite
    let updated = await Test.findOneAndUpdate(
      { _id: test._id },
      { name: 'Dan Smith' },
      { new: true, overwrite: true }
    );
    log(updated);


  } catch (e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }

})()

Producerar:

Mongoose: tests.remove({}, {})
Mongoose: tests.insert({ name: 'john doe', phone: '+12345678901', _id: ObjectId("596efb0ec941ff0ec319ac1e"), __v: 0 })
{
  "__v": 0,
  "name": "john doe",
  "phone": "+12345678901",
  "_id": "596efb0ec941ff0ec319ac1e"
}
Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { '$set': { name: 'Bill S. Preston' } }, { new: true, upsert: false, remove: false, fields: {} })
{
  "_id": "596efb0ec941ff0ec319ac1e",
  "name": "Bill S. Preston",
  "phone": "+12345678901",
  "__v": 0
}
Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { name: 'Dan Smith' }, { new: true, overwrite: true, upsert: false, remove: false, fields: {} })
{
  "_id": "596efb0ec941ff0ec319ac1e",
  "name": "Dan Smith"
}

Att visa dokumentet "skrivs över" eftersom vi undertryckte $set operation som annars skulle ha interpolerats. De två exemplen visas först utan overwrite alternativet, som tillämpar $set modifierare och sedan "med" overwrite alternativet, där objektet du skickade in för "uppdateringen" respekteras och ingen sådan $set modifierare tillämpas.

Notera, det är så här MongoDB Node-drivrutinen gör detta "som standard". Så beteendet att lägga till i den "implicita" $set görs av mangust, såvida du inte säger åt det att inte göra det.

OBS Det sanna sättet att "ersätta" skulle faktiskt vara att använda replaceOne , antingen som API-metoden för replaceOne() eller genom bulkWrite() . overwrite är ett arv av hur mongoose vill tillämpa $set som beskrivs och demonstreras ovan, men MongoDB:s officiella API introducerar replaceOne som en "special" kungen av update() operation som inte tillåter användningen av atomoperatorer som $set i uttalandet och kommer att felas om du försöker.

Detta är mycket tydligare semantiskt eftersom ersätt läser mycket tydligt vad metoden faktiskt används till. Inom standard-API anrop till update() varianter låter dig naturligtvis fortfarande utelämna atomoperatorerna och kommer bara att ersätta innehåll i alla fall. Men varningar bör förväntas.



  1. Få bara ett specificerat fält i MongoDB med C#

  2. bästa praxis för django + PyMongo pooling?

  3. Skip/Mock Redis In Junit

  4. Så här visar du din featureCompatibilityVersion i MongoDB