Om jag i grund och botten förstår din kärna vill du i princip göra det
- Dra objektet som inte krävs från din referensarray
- Ställ in värdet på ditt huvudreferensfält till det första elementet i den ändrade arrayen
Och få det gjort allt i en uppdatering utan att flytta dokument över tråden.
Men detta går tyvärr inte att göra. Det största problemet med detta är att det inte finns något sätt att referera till värdet av ett annat fält i dokumentet som uppdateras. Trots det, för att göra detta utan att iterera skulle du också behöva komma åt den förändrade array för att få det nya första elementet.
Kanske är ett tillvägagångssätt att ompröva ditt schema för att uppnå det du vill. Mitt alternativ här skulle utöka dina referensdokument lite och ta bort behovet av huvudreferensfältet.
Det verkar som att antagandet du är villig att leva med på uppdateringarna är att om den borttagna referensen var huvudreferensen så kan du bara ställa in den nya huvudreferensen till det första elementet i arrayen. Med det i åtanke, överväg följande struktur:
refs: [ { oid: "object1" }, { oid: "object2" }, { oid: "object5", main: true } ]
Genom att ändra dessa till dokument med en oid
egenskap som skulle ställas in på ObjectId det ger möjlighet att ha en ytterligare egenskap på dokumentet som anger vilken som är standard. Detta kan lätt frågas för att fastställa vilket Id som är huvudreferensen.
Tänk nu också på vad som skulle hända om dokumentet som matchar "object5" i oid-fältet drogs från arrayen:
refs: [ { oid: "object1" }, { oid: "object2" } ]
Så när du frågar efter vilken är main-reference
enligt den tidigare logiken accepterar du det första dokumentet i arrayen. Nu, naturligtvis, till dina applikationskrav, om du vill ställa in en annan main-reference
du ändrar bara dokumentet
refs: [ { oid: "object1" }, { oid: "object2", main: true } ]
Och nu återstår logiken att välja array-elementet som har huvudegenskapen som sant skulle förekomma i preferens, och som visas ovan att om den egenskapen inte finns på några element, faller dokumentet tillbaka till det första elementet.
Med allt det sammanfattat blir din operation att dra alla referenser till ett objekt ut ur den arrayen i alla dokument ganska enkel, som gjort i skalet (samma format bör i princip gälla för vilken drivrutin som helst):
db.books.update(
{ "refs.oid": "object5" },
{ $pull: { refs: {oid: "object5"} } }, false, true )
De två extra argumenten till frågan och uppdateringsoperationen är upsert
och multi
respektive. I det här fallet upsert
är inte så vettigt då vi bara vill modifiera dokument som finns, och multi
betyder att vi vill uppdatera allt som matchade. Standard är att bara ändra det första dokumentet.
Naturligtvis förkortade jag all notation men naturligtvis kan värdena vara faktiska ObjectId's enligt din avsikt. Det verkade också rimligt att anta att din huvudsakliga användning av main-reference
är när du har hämtat dokumentet. Definiera en fråga som returnerar main-reference
genom att följa logiken som skisserades borde vara möjligt, men som det ser ut har jag skrivit en hel del här och behöver ta en paus för middag :)
Jag tror att detta är ett värdefullt fall för att ompröva ditt schema för att undvika övertrådiga iterationer för vad du vill uppnå.