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

pushOrModify like-Operator für Mongo-Filialdokument

Dies erfordert tatsächlich "zwei" ( oder "drei" mit upsert ) Aktualisierungsanweisungen und ist einer der sehr guten Gründe, warum "Massen"-Operationen existieren.

db.collection.bulkWrite([
  // Attempt to update the matched element
  { "updateOne": {
    "filter": { 
      "name": "SweetTown",
      "residents.name": "Bob"
    },
    "update": {
      "$set": { "residents.$.reputation": 30 }    
    }
  },
  // $push the element where not matched
  { "updateOne": {
    "filter": {
      "name": "SweetTown",
      "residents.name": { "$ne": "Bob" } 
    },
    "update": { 
      "$push": { 
        "residents": { "name": "Bob", "reputation": 30 } 
      }
    } 
  }}
])

Oder ob Sie tatsächlich ein "upsert" einfügen wollten für das Basisdokument von "SweetTown" dann müssen Sie dieses Anliegen in einen eigenen Test einteilen:

db.collection.bulkWrite([
  // Attempt to update the matched element
  { "updateOne": {
    "filter": { 
      "name": "SweetTown",
      "residents.name": "Bob"
    },
    "update": {
      "$set": { "residents.$.reputation": 30 }    
    }
  },
  // $push the element where not matched
  { "updateOne": {
    "filter": {
      "name": "SweetTown",
      "residents.name": { "$ne": "Bob" } 
    },
    "update": { 
      "$push": { 
        "residents": { "name": "Bob", "reputation": 30 } 
      }
    } 
  }},
  // Only use $setOnInsert when actually an upsert
  { "updateOne": {
      "filter": {
        "name": "SweetTown"
      },
      "update": {
        "$setOnInsert": {
           "residents": [{ "name": "Bob", "reputation": 30 }]
        }
      },
      "upsert": true
  }}
])

Das allgemeine Konzept ist also nur wenden Sie den $setOnInsert an Aktion, wenn ein "upsert" kommt tatsächlich vor. Um sicherzustellen, dass dies nur in diesem Fall geschieht, werden die anderen Operationen, die tatsächlich auf das Array-Element schauen, nicht mit dem "upsert" gekennzeichnet Möglichkeit. Dieser Teil ist Absicht.

Wie man es auch betrachtet, es ist immer nur einer möglich dieser Operationen, um tatsächlich Änderungen in der Datenbank vorzunehmen, da entweder das Element gefunden wird oder nicht, oder sogar das Dokument nicht gefunden und ein neues erstellt wird.

In keinem Fall ist es möglich, diese Art von Operation in einer einzigen Update-Anweisung durchzuführen. Da "Bulk"-Operationen jedoch wirklich nur eine sind Anfrage mit one Antwort, dann brauchte es für Ihre Anwendung nur einmal mit dem Server zu sprechen dass der Server all diese drei Dinge versucht und eine Antwort zurückgibt.

Für die frühere Verwendung der direkten Bulk-API lautet die alternative Syntax:

var bulk = db.collection.initializeOrderedBulkOp();

// $set matched where existing
bulk.find({ "name": "SweetTown", "residents.name": "Bob" }).updateOne({
  "$set": { "residents.$.reputation": 30 }
});

// $push where not existing
bulk.find({ "name": "SweetTown", "residents.name": { "$ne": "Bob" } }).updateOne({
  "$push": { "residents": { "name": "Bob", "reputation": 30 } }
});

// Attempt to upsert only
bulk.find({ "name": "SweetTown" }).upsert().updateOne({
  "$setOnInsert": {
    "residents": [{ "name": "Bob", "reputation": 30 }]
  }
})

bulk.execute();