Vous avez deux collections, des tags et des personnes.
tags modèle:
{
en: String,
sv: String
}
modèle de personne:
{
name: String,
projects: [
title: String,
tags: [
{
type: Schema.ObjectId,
ref: 'tag'
}
]
]
}
Je veux une requête qui renvoie toutes les balises utilisées dans le modèle de personne. Tous les documents.
Sometehing comme
var query = mongoose.model('tag').find({...});
Ou devrais-je en quelque sorte utiliser l'approche globale à cela?
Pour un document particulier, vous pouvez utiliser la fonction populate()
comme
var query = mongoose.model("person").find({ "name": "foo" }).populate("projects.tags");
Et si vous souhaitez rechercher des personnes portant une balise avec «MongoDB» ou «Node JS», par exemple, vous pouvez inclure l'option de requête dans la surcharge de fonction populate()
en tant que:
var query = mongoose.model("person").find({ "name": "foo" }).populate({
"path": "projects.tags",
"match": { "en": { "$in": ["MongoDB", "Node JS"] } }
});
Si vous voulez que toutes les balises existant dans "project.tags"
pour toutes les personnes, le cadre d'agrégation est la voie à suivre. Pensez à exécuter ce pipeline sur la collection de personnes et utilisez l'opérateur $lookup
pour effectuer une jointure à gauche sur la collection de balises:
mongoose.model('person').aggregate([
{ "$unwind": "$projects" },
{ "$unwind": "$projects.tags" },
{
"$lookup": {
"from": "tags",
"localField": "projects.tags",
"foreignField": "_id",
"as": "resultingTagsArray"
}
},
{ "$unwind": "$resultingTagsArray" },
{
"$group": {
"_id": null,
"allTags": { "$addToSet": "$resultingTagsArray" },
"count": { "$sum": 1 }
}
}
]).exec(function(err, results){
console.log(results);
})
Pour une personne donnée, appliquez ensuite un pipeline $match
comme première étape pour filtrer les documents:
mongoose.model('person').aggregate([
{ "$match": { "name": "foo" } },
{ "$unwind": "$projects" },
{ "$unwind": "$projects.tags" },
{
"$lookup": {
"from": "tags",
"localField": "projects.tags",
"foreignField": "_id",
"as": "resultingTagsArray"
}
},
{ "$unwind": "$resultingTagsArray" },
{
"$group": {
"_id": null,
"allTags": { "$addToSet": "$resultingTagsArray" },
"count": { "$sum": 1 }
}
}
]).exec(function(err, results){
console.log(results);
})
Une autre solution de contournement si vous utilisez des versions de MongoDB> = 2.6 ou <= 3.0 qui ne prennent pas en charge l'opérateur $lookup
consiste à renseigner les résultats de l'agrégation de la manière suivante:
mongoose.model('person').aggregate([
{ "$unwind": "$projects" },
{ "$unwind": "$projects.tags" },
{
"$group": {
"_id": null,
"allTags": { "$addToSet": "$projects.tags" }
}
}
], function(err, result) {
mongoose.model('person')
.populate(result, { "path": "allTags" }, function(err, results) {
if (err) throw err;
console.log(JSON.stringify(results, undefined, 4 ));
});
});
Si vous utilisez MongoDb version 3.2, vous pouvez utiliser $ lookup qui effectue une jointure externe gauche.