96 votes

MongoDB interroge plusieurs collections à la fois

users
{
 "_id":"12345",
 "admin":1
},
{
 "_id":"123456789",
 "admin":0
}

posts
{
 "content":"Some content",
 "owner_id":"12345",
 "via":"facebook"
},
{
 "content":"Some other content",
 "owner_id":"123456789",
 "via":"facebook"
}

Voici un échantillon de mon mongodb. Je veux obtenir tous les messages dont l'attribut "via" est égal à "facebook" et qui ont été postés par un administrateur ("admin":1). Je n'ai pas réussi à trouver comment acquérir cette requête. Comme mongodb n'est pas une base de données relationnelle, je n'ai pas pu faire d'opération de jointure. Quelle pourrait être la solution ?

72voto

Shubham Verma Points 2132

Vous pouvez utiliser $lookup ( multiple ) pour obtenir les enregistrements de plusieurs collections :

Exemple :

Si vous avez plus de collections (j'ai 3 collections pour la démo ici, vous pouvez en avoir plus de 3). et je veux obtenir les données de 3 collections dans un seul objet :

La collection est la suivante :

db.doc1.find().pretty() ;

{
    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma"
}

db.doc2.find().pretty() ;

{
    "_id" : ObjectId("5901a5f83541b7d5d3293768"),
    "userId" : ObjectId("5901a4c63541b7d5d3293766"),
    "address" : "Gurgaon",
    "mob" : "9876543211"
}

db.doc3.find().pretty() ;

{
    "_id" : ObjectId("5901b0f6d318b072ceea44fb"),
    "userId" : ObjectId("5901a4c63541b7d5d3293766"),
    "fbURLs" : "http://www.facebook.com",
    "twitterURLs" : "http://www.twitter.com"
}

Maintenant, votre requête sera la suivante :

db.doc1.aggregate([
    { $match: { _id: ObjectId("5901a4c63541b7d5d3293766") } },
    {
        $lookup:
        {
            from: "doc2",
            localField: "_id",
            foreignField: "userId",
            as: "address"
        }
    },
    {
        $unwind: "$address"
    },
    {
        $project: {
            __v: 0,
            "address.__v": 0,
            "address._id": 0,
            "address.userId": 0,
            "address.mob": 0
        }
    },
    {
        $lookup:
        {
            from: "doc3",
            localField: "_id",
            foreignField: "userId",
            as: "social"
        }
    },
    {
        $unwind: "$social"
    },

  {   
    $project: {      
           __v: 0,      
           "social.__v": 0,      
           "social._id": 0,      
           "social.userId": 0
       }
 }

]).pretty();

Alors votre résultat sera :

{
    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma",

    "address" : {
        "address" : "Gurgaon"
    },
    "social" : {
        "fbURLs" : "http://www.facebook.com",
        "twitterURLs" : "http://www.twitter.com"
    }
}

Si vous voulez tous les enregistrements de chaque collection, vous devez supprimer la ligne ci-dessous de la requête :

{
            $project: {
                __v: 0,
                "address.__v": 0,
                "address._id": 0,
                "address.userId": 0,
                "address.mob": 0
            }
        }

{   
        $project: {      
               "social.__v": 0,      
               "social._id": 0,      
               "social.userId": 0
           }
     }

Après avoir supprimé le code ci-dessus, vous obtiendrez l'enregistrement total :

{
    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma",
    "address" : {
        "_id" : ObjectId("5901a5f83541b7d5d3293768"),
        "userId" : ObjectId("5901a4c63541b7d5d3293766"),
        "address" : "Gurgaon",
        "mob" : "9876543211"
    },
    "social" : {
        "_id" : ObjectId("5901b0f6d318b072ceea44fb"),
        "userId" : ObjectId("5901a4c63541b7d5d3293766"),
        "fbURLs" : "http://www.facebook.com",
        "twitterURLs" : "http://www.twitter.com"
    }
}

0 votes

Bonjour, @Shubham Verma, comment obtenir les enregistrements multiples des collections "social" ou "adresse" dans la même requête. Par exemple, j'ai plusieurs enregistrements dans les collections sociales pour un seul utilisateur.

59voto

Charles Hooper Points 1311

Essayer de faire un JOIN dans MongoDB irait à l'encontre de l'objectif de l'utilisation de MongoDB. Vous pouvez toutefois utiliser un DBref et écrivez le code (ou la bibliothèque) de votre application de manière à ce qu'il récupère automatiquement ces références pour vous.

Ou vous pouvez modifier votre schéma et utiliser documents intégrés .

Votre dernier choix est de laisser les choses exactement comme elles sont maintenant et de faire deux requêtes.

1 votes

Comment s'y prendre pour rédiger deux requêtes à ce sujet ?

0 votes

Doctrine MongoDB ODM est une bibliothèque décente pour gérer de telles choses. Cependant, elle ne vous permet de vous joindre qu'à travers une couche de références ; vous ne pouvez pas remplir des références dans des références dans des références avec un certain degré de facilité syntaxique.

1 votes

Comment pourrait-on y parvenir avec de simples requêtes dans MongoJS ?

32voto

Anish Agarwal Points 1173

Voici la réponse à votre question.

db.getCollection('users').aggregate([
    {$match : {admin : 1}},
    {$lookup: {from: "posts",localField: "_id",foreignField: "owner_id",as: "posts"}},
    {$project : {
            posts : { $filter : {input : "$posts"  , as : "post", cond : { $eq : ['$$post.via' , 'facebook'] } } },
            admin : 1

        }}

])

Vous pouvez également choisir l'option de groupe mongodb.

db.getCollection('users').aggregate([
    {$match : {admin : 1}},
    {$lookup: {from: "posts",localField: "_id",foreignField: "owner_id",as: "posts"}},
    {$unwind : "$posts"},
    {$match : {"posts.via":"facebook"}},
    { $group : {
            _id : "$_id",
            posts : {$push : "$posts"}
    }}
])

0 votes

Qu'est-ce que cela fait ? Est-ce une requête ou est-ce que cela ajoute ces métadonnées à la collection ?

1 votes

L'opérateur $lookup est nouveau depuis la version 3.2 et ressemble à une jointure externe gauche. Voir docs.mongodb.com/manual/reference/operator/aggregation/lookup

11voto

almoraleslopez Points 321

Comme mentionné précédemment, dans MongoDB, vous ne pouvez pas effectuer de JOIN entre les collections.

Pour votre exemple, une solution pourrait être :

var myCursor = db.users.find({admin:1});
var user_id = myCursor.hasNext() ? myCursor.next() : null;
db.posts.find({owner_id : user_id._id});

Voir le manuel de référence - section curseurs : http://es.docs.mongodb.org/manual/core/cursors/

Une autre solution serait d'intégrer les utilisateurs dans la collection de messages, mais je pense que pour la plupart des applications web, la collection d'utilisateurs doit être indépendante pour des raisons de sécurité. La collection d'utilisateurs peut avoir des rôles, des permissions, etc.

posts
{
 "content":"Some content",
 "user":{"_id":"12345", "admin":1},
 "via":"facebook"
},
{
 "content":"Some other content",
 "user":{"_id":"123456789", "admin":0},
 "via":"facebook"
}

et ensuite :

db.posts.find({user.admin: 1 });

4voto

Andreas Jung Points 1

Effectuez des requêtes multiples, utilisez des documents intégrés ou consultez les "références de la base de données".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X