web-dev-qa-db-ja.com

MongoDBが複数のコレクションを一度にクエリする

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

これが私のmongodbのサンプルです。 「facebook」に等しい「via」属性を持ち、管理者(「admin」:1)によって投稿されたすべての投稿を取得したい。このクエリを取得する方法がわかりませんでした。 mongodbはリレーショナルデータベースではないため、結合操作を実行できませんでした。解決策は何ですか?

63

MongoDBに参加しようとすると、MongoDBを使用する目的が失われます。ただし、 DBref を使用して、アプリケーションレベルのコード(またはライブラリ)を記述し、これらの参照を自動的に取得することもできます。

または、スキーマを変更して 埋め込みドキュメント を使用できます。

最終的な選択は、現在の状態のままにしておき、2つのクエリを実行することです。

46
Charles Hooper

ここにあなたの質問に対する答えがあります。

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

        }}

])

または、mongodb groupオプションを使用できます。

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"}
    }}
])
17
Anish Agarwal

$lookup(multiple)を使用して、複数のコレクションからレコードを取得できます:

例:

さらにコレクションがある場合(ここではデモ用に3つのコレクションがありますが、3つ以上持つことができます)。そして、私は単一のオブジェクトの3つのコレクションからデータを取得したい:

コレクションは次のとおりです

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

これでクエリは次のようになります:

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

その場合、結果は次のようになります

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

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

各コレクションのすべてのレコードが必要な場合は、クエリから次の行を削除する必要があります:

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

上記のコードを削除すると、合計レコードは次のようになります

{
    "_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"
    }
}
15
Shubham Verma

MongoDBで前述したように、コレクション間で結合することはできません。

たとえば、ソリューションは次のようになります。

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

リファレンスマニュアルのカーソルセクションを参照してください: http://es.docs.mongodb.org/manual/core/cursors/

他の解決策は、ユーザーを投稿コレクションに埋め込むことですが、ほとんどのWebアプリケーションでは、ユーザーコレクションはセキュリティ上の理由から独立している必要があると思います。ユーザーコレクションには、ロール、権限などが含まれる場合があります。

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

その後:

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

複数のクエリを実行するか、埋め込みドキュメントを使用するか、「データベース参照」を確認します。

3
Andreas Jung

1つの解決策:投稿コレクションドキュメントにisAdmin:0/1フラグを追加します。

その他の解決策:DBrefを使用する

2
kheya

以下のようにサンプルJavaScriptを記述し、必要に応じて関数を呼び出すことができます。

次の図を参照してください。 http://dbversity.com/mongodb-querying-multiple-collections-with-a-javascript/

function colListQuery() {
var tcol = new Array()
tcol= db.getCollectionNames();
for(var i = 1; i < tcol.length ; i++) {
query = “db.” + tcol[i] + “.find()”;

var docs= eval(query);
docs.forEach( function(doc, index){ print( “Database_Name:”, db, “Collection_Name:”, tcol[i], “x_value:”, doc.x, “_id:”, doc._id) });

}
}

次に、イラストに示されているように、必要に応じてcolListQuery()で呼び出します。

1
dbversity