Mongoose: Kann ich einen eindeutigen Index für Filialdokumente erstellen?

Erstellt am 4. Aug. 2014  ·  16Kommentare  ·  Quelle: Automattic/mongoose

Ist es möglich, einen eindeutigen Index für Filialdokumente zu erstellen? Ich meine, es kann in einem anderen Filialdokument dupliziert werden, aber nicht im selben Elternteil,

Hilfreichster Kommentar

Ich habe etwas anderes herausgefunden, das auch bei gleichzeitigen Updates zu funktionieren scheint.

Nehmen wir an, subdocs.name ist der Wert, den wir eindeutig haben wollen:

Model.update({
  _id: '576328595b2880f831413b92',
  'subdocs.name': {
    $ne: 'Unique Name'
  }
}, {
  $push: {
    subdocs: {
      name: 'Unique Name'
    }
  }
}).then((raw) => {
  // check raw.nModified value
}).catch(next);

Alle 16 Kommentare

Eine Kombination aus einem Index für das Filialdokument und dem Operator $addToSet sollte Ihnen das geben, wonach Sie suchen. Verwenden Sie einfach $addToSet wenn Sie dem Array hinzufügen, und Sie sollten Duplikate im übergeordneten Dokument vermeiden.

$addToSet funktioniert, aber es erkennt auch andere Filialdokumente in einem anderen übergeordneten Element. Korrigiere mich, wenn ich falsch liege, weil ich es gerade getestet habe

Ich glaube, ich verstehe nicht, was Sie mit Filialdokument in einem anderen Elternteil meinen. Können Sie ein Codebeispiel bereitstellen, das zeigt, was Sie tun möchten?

Entschuldigung für die Beule, aber als ich nach einer Lösung suchte, dachte ich, dass dies in Zukunft helfen könnte:

const schema = new Schema({
  value: String,
  another: Number,
  subdocs: [{
    prop: String, /* Should be unique */
    value: Number
  }]
});

/**
 * Check for duplicated sub document properties.
 */
schema.pre('validate', function validate(next) {
  var unique = [];

  for (var i = 0, l = this.subdocs.length; i < l; i++) {
    let prop = this.subdocs[i].prop;

    if (unique.indexOf(prop) > -1) {
      return next(new Error('Duplicated sub document!'));
    }

    unique.push(prop);
  }

  next();
});

Erläuterung:

Nehmen wir an, wir haben ein Schema mit einer subdocs Eigenschaft, die eine Menge von subdoc mit einer Eigenschaft namens prop , die eindeutig sein muss. Die Idee ist, die duplizierten Eigenschaften in einem Array namens unique zu verfolgen und zu prüfen, ob sich das nächste bereits im Array unique .

Ich weiß, es ist nicht super effizient, aber es funktioniert.

Sicher, das funktioniert meistens, aber denken Sie daran, dass, wenn Sie .push() für ein Array und dann .save() ausführen, daraus ein $push an mongodb wird, also können Sie haben zwei Dokumente denken , dass sie eine einzigartige SubDoc sind sparend , weil sie nicht wissen , sie sind .push() das gleiche -Ing.

@vkarpov15 Der Push erfolgt an das Array unique , das nur die Werte enthält, die eindeutig sein sollen, damit Sie überprüfen können, ob neue Werte ebenfalls eindeutig sind. Es soll verwendet werden, nachdem Sie push oder addToSet aber bevor Sie das Dokument speichern. Das Array unique ist temporär und nicht Teil des Mongo-Dokuments :)

Nö, das ist nebensächlich. Angenommen, Sie versuchen, ungefähr gleichzeitig zwei Dokumente aus verschiedenen JS-Programmen zu speichern - beide machen .find() für das Dokument, schieben auf ein Unterdokument mit prop = 'test' und versuchen zu speichern . Beide werden denken, dass es in Ordnung ist, prop = 'test' einzufügen, weil ihre lokalen Kopien des Dokuments dieses Unterdokument noch nicht haben, also werden beide erfolgreich $push in mongodb einfügen. Das Problem ist, dass das Ausführen von .push() auf einem Mungo-Array zu einem $push in mongodb führt.

@vkarpov15 guter Punkt, habe es nicht für gleichzeitige Einfügungen gedacht. Nun, das scheint viel komplexer zu sein, aber ich werde versuchen, es herauszufinden :)

Nun, Ihr Ansatz funktioniert, solange Sie markModified im props-Array aufrufen, _bevor_ push aufgerufen wird

Ich habe etwas anderes herausgefunden, das auch bei gleichzeitigen Updates zu funktionieren scheint.

Nehmen wir an, subdocs.name ist der Wert, den wir eindeutig haben wollen:

Model.update({
  _id: '576328595b2880f831413b92',
  'subdocs.name': {
    $ne: 'Unique Name'
  }
}, {
  $push: {
    subdocs: {
      name: 'Unique Name'
    }
  }
}).then((raw) => {
  // check raw.nModified value
}).catch(next);

Tolle Idee 👍 das sollte gut gehen

🙌

@stgogm Sie haben gerade eine 5-stündige Suche beendet, und dafür bin ich dankbar.

@vkarpov15 können Sie mir ein Beispiel dafür geben, wie $addToSet die Eindeutigkeit von Unterdokumentenfeldern sicherstellen kann?

Ich habe das probiert

await Course.updateOne({ _id: id }, { $addToSet: { 'units.level': { name: body.name, level: body.level} } }) unitSchema.index({ level: 1 })
Aber unit.level akzeptiert immer noch Duplikate

@ksuhiyp unitSchema.index({ level: 1 }, { unique: true }) und stellen Sie sicher, dass Sie auch _id in unitSchema auf false setzen, wie:

const unitSchema = new Schema({ name: String, level: Number }, { _id: false })

$addToSet funktioniert mit Unterdokumenten, aber es sucht nach exakter Gleichheit zwischen Dokumenten. Wenn also ein Unterdokument ein _id dann wird $addToSet niemals ein Duplikat abfangen. Sehen:

Danke an @vkarpov15 Du hast mich gerettet.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen