MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Objekt nach mehreren Kriterien aus verschachteltem Array entfernen

Sie können $pull die "erste Übereinstimmung" aus dem "äußeren Array" durch Entfernen "aller inneren Elemente", indem Sie einfach Folgendes tun:

db.Events.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$.DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

Das ist in Ordnung, wenn Sie immer nur einen Eintrag in den "Distributions" haben array oder zumindest einer dieser Einträge hat untergeordnete Array-Einträge, die der Bedingung entsprechen würden. So funktioniert das positionelle $ Operator funktioniert mit allen Versionen von MongoDB.

Wenn die Daten "mehrere" Übereinstimmungen in den "äußeren" "Distributions" aufweisen würden array dann, wenn Sie MongoDB 3.6 haben, können Sie den positionsgefilterten $[<identifier>] anwenden Operator zum Ändern aller übereinstimmenden Einträge:

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 diesem Fall die arrayFilters Option definiert eine Bedingung, mit der wir Einträge im "äußeren" Array abgleichen, so dass dies tatsächlich für alles gelten kann, was abgeglichen wird.

Oder tatsächlich seit $pull im Wesentlichen diese Bedingungen selbst hat, dann können Sie alternativ einfach die Position all $[] verwenden Operator in diesem Fall:

db.Event.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$[].DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

In beiden Fällen wird das Dokument in der Frage geändert, indem das innere Element mit allen null entfernt wird Tasten:

{
        "_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")
                        ]
                }
        ]
}

Die "Abfrage"-Bedingungen verwenden alle $elemMatch zur Dokumentenauswahl. Dies ist eigentlich für das positionelle $ erforderlich Operator, um den "Positionsindex" zu erhalten, der für die "erste Übereinstimmung" verwendet wird. Obwohl dies eigentlich keine "Anforderung" für den positionsgefilterten $[<identifier>] ist oder die positionellen alle $[] Operator, es ist immer noch nützlich, damit Sie nicht einmal Dokumente für die Aktualisierung in Betracht ziehen, die nicht den späteren Aktualisierungsbedingungen von entweder $pull entsprechen oder die arrayFilters Optionen.

Wie für $pull selbst gelten die Bedingungen hier tatsächlich für "jedes" Array-Element, daher besteht keine Notwendigkeit für $elemMatch in dieser Operation, da wir bereits auf der "Element"-Ebene suchen.

Das dritte Beispiel zeigt, dass die Position alle $[] sind Operator kann einfach diese $pull verwenden Bedingungen unter Berücksichtigung jedes "inneren" Array-Elements und gelten nur für ALLE "äußeren" Array-Elemente. Also der eigentliche Punkt des positionsgefilterten $[<identifier>] expression soll "nur" die "äußeren" Array-Elemente verarbeiten, die tatsächlich der "inneren" Bedingung entsprechen. Daher verwenden wir $elemMatch bei der Überlegung, jedes "innere" Array-Element abzugleichen.

Wenn Sie nicht MongoDB 3.6 haben, verwenden Sie mindestens das erste Formular und wiederholen das wahrscheinlich, bis die Updates schließlich keine geänderten Dokumente mehr zurückgeben, die darauf hinweisen, dass keine Elemente mehr übrig sind, die der Bedingung entsprechen.

Es gibt eine viel detailliertere Beschreibung der "Alternativen" als Ansätze unter So aktualisieren Sie mehrere Array-Elemente in Mongodb, aber solange Ihre Daten entweder für den ursprünglichen Fall geeignet sind oder MongoDB 3.6 tatsächlich verfügbar ist, ist dies das Richtige Ansatz hier.

Wenn Sie die volle Wirkung der neuen Syntax für MongoDB 3.6 sehen möchten. Dies ist die Änderung des Dokuments in der Frage, mit der ich die Update-Anweisungen hier überprüft habe:

{
    "_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")
                    ]
            }
    ]
}

Was im Grunde einige Einträge sowohl "außen" als auch "innen" dupliziert, um zu zeigen, wie die Anweisung alle null entfernt Werte.

HINWEIS arrayFilters werden im "options"-Argument für .update() angegeben und wie Methoden ist die Syntax im Allgemeinen mit allen neueren Treiberversionen kompatibel und sogar mit denen vor der Veröffentlichung von MongoDB 3.6.

Dies gilt jedoch nicht für den mongo Shell, da die Art und Weise, wie die Methode dort implementiert ist ( "ironischerweise aus Gründen der Abwärtskompatibilität"), die arrayFilters -Argument wird nicht erkannt und von einer internen Methode entfernt, die die Optionen parst, um „Abwärtskompatibilität“ mit früheren MongoDB-Serverversionen und einem „alten“ .update() bereitzustellen API-Aufrufsyntax.

Wenn Sie also den Befehl in der mongo verwenden möchten Shell oder andere "Shell-basierte" Produkte (insbesondere Robo 3T ) benötigen Sie eine neueste Version entweder aus dem Entwicklungszweig oder aus der Produktionsversion ab 3.6 oder höher.

Robo 3T ist insbesondere hier immer noch daran gebunden, auf einer MongoDB 3.4-Shell zu basieren. Selbst wenn Sie also eine Verbindung zu einer leistungsfähigen MongoDB 3.6-Instanz herstellen, werden diese Optionen von diesem Programm nicht an den Server weitergegeben. Es wird empfohlen, nur bei der Shell und den unterstützten Produkten zu bleiben, obwohl es einige andere Angebote gibt, die nicht die gleiche Einschränkung haben.