MongoDB wyszukuje wiele kolekcji naraz

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"
}
Oto próbka z mojego mongodb. Chcę uzyskać wszystkie posty, które mają atrybut" via "równy" facebook " i wysłany przez admina ("admin": 1). Nie mogłem wymyślić, jak zdobyć to zapytanie. Ponieważ mongodb nie jest relacyjną bazą danych, nie mogłem wykonać operacji join. Jakie może być rozwiązanie ?
Author: Sarpdoruk Tahmaz, 2011-06-28

6 answers

Próba przyłączenia się do MongoDB nie udałoby się użyć MongoDB. Możesz jednak użyć DBref i napisać kod (lub bibliotekę) na poziomie aplikacji, aby automatycznie pobierał te odniesienia dla Ciebie.

LUB możesz zmienić swój schemat i użyć wbudowanych dokumentów .

Twoim ostatecznym wyborem jest zostawić rzeczy dokładnie takie, jakie są teraz i zrobić dwa zapytania.

 54
Author: Charles Hooper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 07:02:17

Możesz użyć $lookup (multiple), aby pobrać rekordy z wielu kolekcji:

Przykład:

Jeśli masz więcej kolekcji (ja mam 3 kolekcje na demo tutaj, możesz mieć więcej niż 3 ). i chcę pobrać dane z 3 kolekcji w jednym obiekcie:

Kolekcja to as:

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"
}

Teraz Twoje zapytanie będzie następujące:

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();

Wtedy twój wynik będzie:

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

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

Jeśli chcesz wszystkie rekordy z każdej kolekcji, powinieneś usunąć poniższy wiersz z zapytania:

{
            $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
           }
     }

Po usunięciu powyższego kodu otrzymasz całkowity rekord as:

{
    "_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"
    }
}
 36
Author: Shubham Verma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-27 09:20:36

Oto odpowiedź na twoje pytanie.

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

        }}

])

Albo możesz wybrać opcję grupy 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"}
    }}
])
 22
Author: Anish Agarwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-01 15:29:39

Jak wspomniano wcześniej w MongoDB, nie można łączyć kolekcji.

Dla Twojego przykładu rozwiązaniem może być:

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

Zobacz sekcję podręczniki referencyjne - Kursory: http://es.docs.mongodb.org/manual/core/cursors/

Innym rozwiązaniem byłoby osadzenie użytkowników w kolekcji postów, ale myślę, że dla większości aplikacji internetowych zbiór użytkowników musi być niezależny ze względów bezpieczeństwa. Zbiór użytkowników może mieć role, zezwolenia itp.

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

Oraz wtedy:

db.posts.find({user.admin: 1 });
 9
Author: almoraleslopez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-13 12:57:56

Wykonaj wiele zapytań lub użyj osadzonych dokumentów lub spójrz na "odniesienia do bazy danych".

 3
Author: Andreas Jung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 06:53:04

Jedno rozwiązanie: dodaj flagę isAdmin: 0/1 do dokumentu kolekcji postów.

Inne rozwiązanie: użyj DBrefs

 2
Author: kheya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 06:53:36