sql >> Databáze >  >> NoSQL >> MongoDB

Mongoose přepíše dokument spíše než pole `$set`

Ve skutečnosti, ale vzhledem k tomu, že se mongoose ve skutečnosti "plete" s aktualizací pod krytem, ​​je to ve skutečnosti výchozí akce vašeho odeslání do běžné funkce MongoDB.

Mangoose tedy považuje za „moudré“ pohodlný způsob „předpokládat“, že jste chtěli vydat $set návod zde. Protože to v tomto případě ve skutečnosti nechcete udělat, vypnete toto chování pomocí { overwrite: true } v možnostech předávaných libovolnému .update() metoda:

Jako úplný příklad:

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

})()

Vyrábí:

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

Zobrazení dokumentu je "přepsáno", protože jsme potlačili $set operace, která by jinak byla interpolována. Dvě ukázky se zobrazí jako první bez overwrite možnost, která použije $set modifikátor a poté "pomocí" overwrite možnost, kde je respektován objekt, který jste předali pro "aktualizaci", a žádná taková $set je použit modifikátor.

Všimněte si, že takto to dělá ovladač MongoDB Node „ve výchozím nastavení“. Tedy chování přidání do "implicitní" $set provádí mangusta, pokud jí neřeknete, aby to nedělalo.

POZNÁMKA Skutečným způsobem "nahradit" by ve skutečnosti bylo použití replaceOne , buď jako metodu API replaceOne() nebo pomocí bulkWrite() . overwrite je dědictvím toho, jak chce mongoose použít $set jak je popsáno a ukázáno výše, nicméně oficiální API MongoDB zavádí replaceOne jako "speciál" král update() operaci, kterou neumožňuje použití atomických operátorů jako $set v příkazu a pokud to zkusíte, dojde k chybě.

Od nahradit je to sémanticky mnohem jasnější velmi jasně čte, k čemu se metoda vlastně používá. V rámci standardních volání API na update() varianty samozřejmě stále umožňují vynechat atomické operátory a pouze je nahradí obsah každopádně. Ale měli byste očekávat varování.



  1. Cizí klíče v mongo?

  2. Cassandra vs. MongoDB:který z nich byste si měli vybrat

  3. Chyba při připojování k serveru MongoDb Atlas Server

  4. Vytáhněte záznam z pole přes Meteor