In MongoDB, de $setDifference
aggregatiepijplijnoperator accepteert twee sets en voert een relatieve aanvulling uit van de tweede set ten opzichte van de eerste. Het geeft een array terug met de elementen die alleen in de eerste set voorkomen.
$setDifference
accepteert twee argumenten, die beide elke geldige expressie kunnen zijn, zolang ze elk naar een array worden omgezet. $setDifference
behandelt de arrays als sets.
Voorbeeld
Stel dat we een verzameling hebben met de naam data
met de volgende documenten:
{ "_id" : 1, "a" : [ 1, 2, 3 ], "b" : [ 1, 2, 3 ] } { "_id" : 2, "a" : [ 1, 2, 3 ], "b" : [ 1, 2 ] } { "_id" : 3, "a" : [ 1, 2 ], "b" : [ 1, 2, 3 ] } { "_id" : 4, "a" : [ 1, 2, 3 ], "b" : [ 3, 4, 5 ] } { "_id" : 5, "a" : [ 1, 2, 3 ], "b" : [ 4, 5, 6 ] }
We kunnen de $setDifference
. toepassen operator tegen de a
en b
velden in die documenten.
Voorbeeld:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 1, 2, 3, 4, 5 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
{ "a" : [ 1, 2, 3 ], "b" : [ 1, 2, 3 ], "result" : [ ] } { "a" : [ 1, 2, 3 ], "b" : [ 1, 2 ], "result" : [ 3 ] } { "a" : [ 1, 2 ], "b" : [ 1, 2, 3 ], "result" : [ ] } { "a" : [ 1, 2, 3 ], "b" : [ 3, 4, 5 ], "result" : [ 1, 2 ] } { "a" : [ 1, 2, 3 ], "b" : [ 4, 5, 6 ], "result" : [ 1, 2, 3 ] }
Geneste arrays
De $setDifference
operator daalt niet af in geneste arrays. Het evalueert alleen arrays op het hoogste niveau.
Stel dat onze collectie ook de volgende documenten bevat:
{ "_id" : 6, "a" : [ 1, 2, 3 ], "b" : [ [ 1, 2, 3 ] ] } { "_id" : 7, "a" : [ 1, 2, 3 ], "b" : [ [ 1, 2 ], 3 ] }
En we passen $setDifference
toe naar die twee documenten:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 6, 7 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
{ "a" : [ 1, 2, 3 ], "b" : [ [ 1, 2, 3 ] ], "result" : [ 1, 2, 3 ] } { "a" : [ 1, 2, 3 ], "b" : [ [ 1, 2 ], 3 ], "result" : [ 1, 2 ] }
In het eerste document, de b
veld bevatte een array die slechts één element bevatte - een andere array. In dit geval is de buitenste array geëvalueerd en bleek deze niet dezelfde waarden te bevatten als in de array op a
.
Als de a
veld zelf een geneste array had bevat, was het misschien een ander verhaal geweest.
Stel dat we de volgende documenten hebben:
{ "_id" : 8, "a" : [ [ 1, 2, 3 ] ], "b" : [ [ 1, 2, 3 ] ] } { "_id" : 9, "a" : [ [ 1, 2, 3 ] ], "b" : [ [ 1, 2 ], 3 ] }
En we passen $setDifference
toe naar die documenten:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 8, 9 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
{ "a" : [ [ 1, 2, 3 ] ], "b" : [ [ 1, 2, 3 ] ], "result" : [ ] } { "a" : [ [ 1, 2, 3 ] ], "b" : [ [ 1, 2 ], 3 ], "result" : [ [ 1, 2, 3 ] ] }
In het eerste document, a
komt overeen met b
precies, en dus is het resultaat een lege array.
In het tweede document, de geneste array op a
is anders dan de geneste array op b
, en dus de hele geneste array van a
wordt geretourneerd.
Ontbrekende velden
$setDifference
toepassen naar een niet-bestaand veld resulteert in null
.
Bekijk de volgende documenten:
{ "_id" : 10, "a" : [ 1, 2, 3 ] } { "_id" : 11, "b" : [ 1, 2, 3 ] } { "_id" : 12 }
Het eerste document heeft geen b
veld, heeft het tweede document geen a
veld, en het derde document heeft geen van beide.
Dit is wat er gebeurt als we $setDifference
toepassen naar de a
en b
velden:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 10, 11, 12 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
{ "a" : [ 1, 2, 3 ], "result" : null } { "b" : [ 1, 2, 3 ], "result" : null } { "result" : null }
Onjuist gegevenstype
Beide operanden van $setDifference
moeten arrays zijn. Als dat niet het geval is, wordt er een fout gegenereerd.
Stel dat onze collectie de volgende documenten bevat:
{ "_id" : 13, "a" : [ 1, 2, 3 ], "b" : 3 } { "_id" : 14, "a" : 3, "b" : [ 1, 2, 3 ] } { "_id" : 15, "a" : 2, "b" : 3 }
En we passen $setDifference
toe naar die documenten:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 13, 14, 15 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "both operands of $setDifference must be arrays. Second argument is of type: double", "code" : 17049, "codeName" : "Location17049" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Dubbele waarden
De $setDifference
operator filtert duplicaten uit het resultaat om een array uit te voeren die alleen unieke items bevat. Ook is de volgorde van de elementen in de uitvoerarray niet gespecificeerd.
Stel dat we de volgende documenten hebben:
{ "_id" : 16, "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ 1, 2, 3 ] } { "_id" : 17, "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ 1, 2 ] } { "_id" : 18, "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ ] } { "_id" : 19, "a" : [ 3, 2, 1, 2, 3, 1 ], "b" : [ 2, 3, 1 ] } { "_id" : 20, "a" : [ 1, 3, 2, 2, 3, 1 ], "b" : [ 2, 1 ] } { "_id" : 21, "a" : [ 2, 3, 1, 2, 3, 1 ], "b" : [ ] }
Dan passen we de $setDifference
. toe operator voor hen:
db.data.aggregate(
[
{ $match: { _id: { $in: [ 16, 17, 18, 19, 20, 21 ] } } },
{
$project:
{
_id: 0,
a: 1,
b: 1,
result: { $setDifference: [ "$a", "$b" ] }
}
}
]
)
Resultaat:
{ "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ 1, 2, 3 ], "result" : [ ] } { "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ 1, 2 ], "result" : [ 3 ] } { "a" : [ 1, 1, 2, 2, 3, 3 ], "b" : [ ], "result" : [ 1, 2, 3 ] } { "a" : [ 3, 2, 1, 2, 3, 1 ], "b" : [ 2, 3, 1 ], "result" : [ ] } { "a" : [ 1, 3, 2, 2, 3, 1 ], "b" : [ 2, 1 ], "result" : [ 3 ] } { "a" : [ 2, 3, 1, 2, 3, 1 ], "b" : [ ], "result" : [ 2, 3, 1 ] }