aggregationsramverket
och inte .distinct()
kommando:
db.event.aggregate([
// De-normalize the array content to separate documents
{ "$unwind": "$tags" },
// Filter the de-normalized content to remove non-matches
{ "$match": { "tags": /foo/ } },
// Group the "like" terms as the "key"
{ "$group": {
"_id": "$tags"
}}
])
Du är förmodligen bättre av att använda ett "ankare" till början av regexet, om du menar från "starten" av strängen. Och gör även detta $match
innan du bearbetar $unwind
likaså:
db.event.aggregate([
// Match the possible documents. Always the best approach
{ "$match": { "tags": /^foo/ } },
// De-normalize the array content to separate documents
{ "$unwind": "$tags" },
// Now "filter" the content to actual matches
{ "$match": { "tags": /^foo/ } },
// Group the "like" terms as the "key"
{ "$group": {
"_id": "$tags"
}}
])
Det säkerställer att du inte bearbetar $unwind
på varje dokument i samlingen och bara de som eventuellt innehåller ditt "matchade taggar"-värde innan du "filtrerar" för att vara säker.
Det riktigt "komplexa" sättet att något minska stora arrayer med möjliga matchningar kräver lite mer arbete, och MongoDB 2.6 eller senare:
db.event.aggregate([
{ "$match": { "tags": /^foo/ } },
{ "$project": {
"tags": { "$setDifference": [
{ "$map": {
"input": "$tags",
"as": "el",
"in": { "$cond": [
{ "$eq": [
{ "$substr": [ "$$el", 0, 3 ] },
"foo"
]},
"$$el",
false
]}
}},
[false]
]}
}},
{ "$unwind": "$tags" },
{ "$group": { "_id": "$tags" }}
])
Så $map
är en trevlig "in-line" processor av arrayer men det kan bara gå så långt. $setDifference
operatorn negerar false
matchningar, men i slutändan behöver du fortfarande bearbeta $unwind
för att göra den återstående $group
steg för distinkta värden totalt sett.
Fördelen här är att arrayer nu "reduceras" till endast "taggar"-elementet som matchar. Använd bara inte detta när du vill ha ett "antal" av förekomsterna när det finns "flera distinkta" värden i samma dokument. Men återigen, det finns andra sätt att hantera det på.