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