Vous pouvez $pull
la "première correspondance" du "tableau externe" en supprimant "tous les éléments internes" simplement en faisant :
db.Events.updateMany(
{
"Distributions.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"$pull": {
"Distributions.$.DistributionData": {
"Key": null,
"Value": null,
"Children": null
}
}
}
)
C'est bien si vous n'avez qu'une seule entrée dans le "Distributions"
array ou au moins une seule de ces entrées a des entrées de tableau enfant qui correspondent à la condition. C'est ainsi que le positionnel $
L'opérateur fonctionne avec toutes les versions de MongoDB.
Si les données auraient des correspondances "multiples" dans les "Distributions"
"externes" tableau alors si vous avez MongoDB 3.6, vous pouvez appliquer le filtre positionnel $[<identifier>]
opérateur pour modifier toutes les entrées correspondantes :
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
}
}}
]
}
)
Dans ce cas, le arrayFilters
L'option définit une condition par laquelle nous faisons correspondre les entrées du tableau "externe" afin que cela puisse en fait s'appliquer à tout ce qui correspond.
Ou bien depuis $pull
a essentiellement ces conditions lui-même, alors vous pouvez alternativement simplement utiliser le positionnel all $[]
opérateur dans ce cas :
db.Event.updateMany(
{
"Distributions.DistributionData": {
"$elemMatch": {
"Key": null,
"Value": null,
"Children": null
}
}
},
{
"$pull": {
"Distributions.$[].DistributionData": {
"Key": null,
"Value": null,
"Children": null
}
}
}
)
Les deux cas modifient le document dans la question en supprimant l'élément interne avec tous les null
clés :
{
"_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")
]
}
]
}
Les conditions "query" utilisent toutes $elemMatch
pour la sélection de documents. Ceci est en fait requis pour le $
positionnel opérateur afin d'obtenir "l'indice de position" utilisé pour la "première correspondance". Bien qu'il ne s'agisse pas réellement d'une "exigence" pour le filtre $[<identifier>]
filtré par position ou le positionnel tout $[]
, il est toujours utile pour que vous ne considériez même pas les documents à mettre à jour qui ne correspondront pas aux conditions de mise à jour ultérieures de l'un ou l'autre des éléments $pull
ou les arrayFilters
options.
Quant au $pull
lui-même, les conditions ici s'appliquent en fait à "chaque" élément du tableau, il n'y a donc pas besoin du $elemMatch
dans cette opération puisque nous regardons déjà le niveau "élément".
Le troisième exemple montre que le positionnel all $[]
l'opérateur peut simplement utiliser ces $pull
conditions en tenant compte de chaque élément de tableau "interne" et s'appliquera uniquement à TOUS les éléments de tableau "externes". Ainsi, le point réel du filtre positionnel $[<identifier>]
expression consiste à traiter "uniquement" les éléments de tableau "externes" qui correspondent réellement à la condition "interne". C'est pourquoi nous utilisons $elemMatch
dans la prise en compte de la correspondance de chaque élément de tableau "interne".
Si vous n'avez pas réellement MongoDB 3.6 au moins, vous utilisez le premier formulaire et le répétez probablement jusqu'à ce que les mises à jour ne renvoient finalement plus de documents modifiés indiquant qu'il ne reste plus d'éléments correspondant à la condition.
Il existe une description beaucoup plus détaillée des "alternatives" en tant qu'approches dans Comment mettre à jour plusieurs éléments de tableau dans mongodb, mais tant que vos données conviennent au cas initial ou que vous disposez réellement de MongoDB 3.6, alors c'est le bon approche ici.
Si vous voulez voir le plein effet de la nouvelle syntaxe pour MongoDB 3.6. c'est la modification du document dans la question que j'ai utilisée pour vérifier les déclarations de mise à jour ici :
{
"_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")
]
}
]
}
Ce qui duplique essentiellement certaines entrées à la fois "externes" et "internes" pour montrer comment l'instruction supprime tous les null
valeurs.
REMARQUE
arrayFilters
sont spécifiés dans l'argument "options" pour.update()
et comme les méthodes, la syntaxe est généralement compatible avec toutes les versions récentes du pilote et même celles antérieures à la sortie de MongoDB 3.6.Cependant, ce n'est pas le cas du
mongo
shell, puisque la façon dont la méthode y est implémentée ("ironiquement pour la compatibilité ascendante") learrayFilters
l'argument n'est pas reconnu et supprimé par une méthode interne qui analyse les options afin de fournir une "compatibilité descendante" avec les versions antérieures du serveur MongoDB et un "héritage".update()
Syntaxe d'appel API.Donc, si vous voulez utiliser la commande dans le
mongo
shell ou d'autres produits "à base de shell" (notamment Robo 3T), vous avez besoin d'une dernière version de la branche de développement ou de la version de production à partir de 3.6 ou supérieure.Robo 3T notamment ici est toujours lié au fait d'être basé sur un shell MongoDB 3.4. Ainsi, même lors de la connexion à une instance MongoDB 3.6 compatible, ces options ne seront pas transmises au serveur à partir de ce programme. Il est conseillé de rester avec le shell et les produits pris en charge uniquement, bien qu'il existe d'autres offres qui n'ont pas la même limitation.