Puoi $pull
la "prima corrispondenza" dall'"array esterno" con la rimozione di "tutti gli elementi interni" semplicemente facendo:
db.Events.updateMany(
{
"Distributions.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"$pull": {
"Distributions.$.DistributionData": {
"Key": null,
"Value": null,
"Children": null
}
}
}
)
Va bene se hai sempre una sola voce in "Distributions"
array o almeno una di queste voci ha voci di array figlio che corrisponderebbero alla condizione. Ecco come il posizionale $
operatore funziona con tutte le versioni di MongoDB.
Se i dati hanno corrispondenze "multiple" nel "Distributions"
"esterno". array quindi se hai MongoDB 3.6 puoi applicare il filtro posizionale $[<identifier>]
operatore per modificare tutte le voci corrispondenti:
db.Events.updateMany(
{
"Distributions.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"$pull": {
"Distributions.$[element].DistributionData": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"arrayFilters": [
{ "element.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}}
]
}
)
In tal caso, gli arrayFilters
l'opzione definisce una condizione in base alla quale abbiniamo le voci nell'array "esterno" in modo che questo possa effettivamente applicarsi a tutto ciò che è abbinato.
O addirittura da $pull
essenzialmente ha queste condizioni stesse, quindi puoi alternativamente usare semplicemente il posizionale all $[]
operatore in questo caso:
db.Event.updateMany(
{
"Distributions.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"$pull": {
"Distributions.$[].DistributionData": {
"Key": null,
"Value": null,
"Children": null
}
}
}
)
In entrambi i casi viene modificato il documento nella domanda rimuovendo l'elemento interno con tutti i null
chiavi:
{
"_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
"CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
"WKT" : "",
"Distributions" : [
{
"_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
"DeliveryType" : 1,
"DistributionData" : [
{
"Key" : "Topic",
"Value" : "Topics",
"Children" : null
},
{
"Key" : "Message",
"Value" : "test",
"Children" : null
}
],
"Schedules" : [
ISODate("2016-05-06T05:09:56.988Z")
]
}
]
}
Le condizioni "query" utilizzano tutte $elemMatch
per la selezione dei documenti. Questo è effettivamente richiesto per il posizionale $
operatore per ottenere l'"indice di posizione" utilizzato per la "prima corrispondenza". Anche se questo non è in realtà un "requisito" per il filtro posizionale $[<identifier>]
o il posizionale all $[]
operatore, è comunque utile in modo da non considerare nemmeno i documenti per l'aggiornamento che non corrisponderanno alle condizioni di aggiornamento successive né del $pull
o gli arrayFilters
opzioni.
Per quanto riguarda il $pull
di per sé, le condizioni qui si applicano effettivamente a "ogni" elemento dell'array, quindi non è necessario il $elemMatch
in tale operazione poiché stiamo già osservando il livello "elemento".
Il terzo esempio mostra che il posizionale all $[]
l'operatore può semplicemente usare quei $pull
condizioni in considerazione di ogni elemento dell'array "interno" e si applicheranno solo a TUTTI gli elementi dell'array "esterni". Quindi il punto effettivo del filtro posizionale $[<identifier>]
espressione è elaborare "solo" quegli elementi dell'array "esterni" che corrispondono effettivamente alla condizione "interna". Ecco perché usiamo $elemMatch
nella considerazione per la corrispondenza di ogni elemento dell'array "interno".
Se in realtà non disponi di MongoDB 3.6 almeno, stai utilizzando il primo modulo e probabilmente lo stai ripetendo fino a quando gli aggiornamenti non restituiscono finalmente documenti modificati che indicano che non sono rimasti più elementi che corrispondono alla condizione.
C'è una scrittura molto più dettagliata sulle "alternative" come approcci a Come aggiornare più elementi di array in mongodb, ma fintanto che i tuoi dati si adattano al caso iniziale o hai effettivamente MongoDB 3.6 disponibile, allora questo è il corretto avvicinati qui.
Se vuoi vedere l'effetto completo della nuova sintassi per MongoDB 3.6. questa è l'alterazione al documento nella domanda che ho usato per verificare le dichiarazioni di aggiornamento qui:
{
"_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
"CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
"WKT" : "",
"Distributions" : [
{
"_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
"DeliveryType" : 1,
"DistributionData" : [
{
"Key" : "Topic",
"Value" : "Topics",
"Children" : null
},
{
"Key" : null,
"Value" : null,
"Children" : null
},
{
"Key" : "Message",
"Value" : "test",
"Children" : null
},
{
"Key" : null,
"Value" : null,
"Children" : null
}
],
"Schedules" : [
ISODate("2016-05-06T05:09:56.988Z")
]
},
{
"_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
"DeliveryType" : 1,
"DistributionData" : [
{
"Key" : "Topic",
"Value" : "Topics",
"Children" : null
},
{
"Key" : null,
"Value" : null,
"Children" : null
},
{
"Key" : "Message",
"Value" : "test",
"Children" : null
},
{
"Key" : null,
"Value" : null,
"Children" : null
}
],
"Schedules" : [
ISODate("2016-05-06T05:09:56.988Z")
]
}
]
}
Che sostanzialmente duplica alcune voci sia "esterna" che "interna" per mostrare come l'istruzione rimuove tutto il null
valori.
NOTA arrayFilters
sono specificati nell'argomento "opzioni" per .update()
e come i metodi, la sintassi è generalmente compatibile con tutte le versioni dei driver di rilascio recenti e anche quelle precedenti al rilascio di MongoDB 3.6.
Tuttavia questo non è vero per il mongo
shell, dal momento che il metodo è implementato lì ("ironicamente per compatibilità con le versioni precedenti") gli arrayFilters
argomento non viene riconosciuto e rimosso da un metodo interno che analizza le opzioni al fine di fornire "compatibilità con le versioni precedenti" con le versioni precedenti del server MongoDB e un "legacy" .update()
Sintassi delle chiamate API.
Quindi, se vuoi usare il comando nel mongo
shell o altri prodotti "shell based" (in particolare Robo 3T) è necessaria una versione più recente dal ramo di sviluppo o dalla versione di produzione a partire dalla 3.6 o successiva.
Robo 3T in particolare qui è ancora legato all'essere basato su una shell MongoDB 3.4. Quindi, anche quando ci si connette a un'istanza MongoDB 3.6 capace, queste opzioni non verranno passate al server da questo programma. Si consiglia di utilizzare solo la shell e i prodotti supportati, anche se esistono altre offerte che non hanno le stesse limitazioni.