MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Rimuovere l'oggetto dall'array nidificato in base a più criteri

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.