MongoDBで同等のSQL結合を実行するにはどうすればよいですか?


498

MongoDBで同等のSQL結合を実行するにはどうすればよいですか?

たとえば、2つのコレクション(ユーザーとコメント)があり、pid = 444のすべてのコメントとそれぞれのユーザー情報を取得したいとします。

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

特定のフィールド(例:... find({pid:444}))を持つすべてのコメントと、各コメントに関連付けられているユーザー情報を一度にプルする方法はありますか?

現時点では、まず自分の基準に一致するコメントを取得してから、その結果セット内のすべてのuidを把握し、ユーザーオブジェクトを取得して、コメントの結果とマージしています。私はそれを間違っているようです。


35
MongoDB 3.2+が$ lookupと呼ばれる結合ソリューションを実装したため、この質問の最後の回答がおそらく最も関連性があります。誰もが最後まで読むとは限らないかもしれないので、私はそれをここにプッシュすると思いました。stackoverflow.com/a/33511166/2593330
thefourtheye

6
正解です。$ lookupはMongoDB 3.2で導入されました。詳細はdocs.mongodb.org/master/reference/operator/aggregation/lookup/…にあります
NDB

回答:


306

Mongo 3.2の時点で、この質問に対する答えはほとんど正しくありません。集約パイプラインに追加された新しい$ lookup演算子は、基本的に左外部結合と同じです。

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup

ドキュメントから:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

もちろん、Mongoはリレーショナルデータベースではありません。開発者は$ lookupの特定のユースケースを推奨するように注意していますが、少なくとも3.2以降では、MongoDBで結合を実行できるようになりました。


@clayton:2つ以上のコレクションはどうですか?
Dipen Dedania 2016年

1
@DipenDedaniaは、$ lookupステージを集計パイプラインに追加するだけです。
Clayton Gulick 2016年

左のコレクションの配列のどのフィールドも、右のコレクションの対応するIDに結合できません。誰かが私を助けてくれますか?
Prateek Singh 2016

1
私はこれについて少し混乱しています-「from」コレクション内の特定のドキュメントのみを必要とすることを指定する方法はありますか、それとも一度にすべてのデータベースに自動的に参加しますか?
user3413723

最新のSpring Data MongoDBが3.2をサポートしているかどうか疑問に思っていますか?
gtiwari333 2016

142

mongodbの公式サイトのこのページは、まさにこの質問に対処しています。

https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/model-data-for-ruby-on-rails.html

記事のリストを表示するときは、記事を投稿したユーザーの名前を表示する必要があります。リレーショナルデータベースを使用している場合、ユーザーとストアで結合を実行し、すべてのオブジェクトを1つのクエリで取得できます。ただし、MongoDBは結合をサポートしていないため、非正規化が必要になる場合があります。ここで、これは 'username'属性をキャッシュすることを意味します。

まるで私たちがいくつかの普遍的な法律に違反しているかのように、リレーショナル純粋主義者たちはすでに不安を感じているかもしれません。ただし、MongoDBコレクションはリレーショナルテーブルと同等ではないことに注意してください。それぞれが独自の設計目標を提供します。正規化されたテーブルは、アトミックで分離されたデータのチャンクを提供します。ただし、ドキュメントはオブジェクト全体をより厳密に表します。ソーシャルニュースサイトの場合、ユーザー名は投稿されるストーリーに固有のものであると主張できます。


51
@dudelgrincenは、正規化およびリレーショナルデータベースからのパラダイムシフトです。NoSQLの目標は、データベースの読み取りと書き込みを非常に高速にすることです。BigDataを使用すると、DBの数が少ないアプリケーションサーバーとフロントエンドサーバーのカスケードができます。1秒間に数百万のトランザクションを実行すると予想されます。負荷の高い作業をデータベースからオフロードし、それをアプリケーションレベルに配置します。詳細な分析が必要な場合は、データをOL​​APデータベースに入れる統合ジョブを実行します。とにかく、OLTPデータベースから多くの深いクエリを取得するべきではありません。
Snowburnt 2013年

18
@dudelgrincenまた、すべてのプロジェクトやデザインに対応しているわけではありません。SQLタイプのデータベースで機能するものがあれば、なぜそれを変更するのですか?noSQLで動作するようにスキーマをマッサージできない場合は、使用しないでください。
Snowburnt 2013年

9
移行と常に進化するスキーマも、NoSQLシステムでの管理がはるかに簡単です。
2014年

14
ユーザーがWebサイトに3.540の投稿を持ち、プロファイルでユーザー名を変更した場合はどうなりますか?すべての投稿を新しいユーザー名で更新する必要がありますか?
Ivo Pereira

2
@IvoPereiraはい、そのため、この方法でデータをモデル化することは避けなければなりません。同じシナリオとその結果を説明する記事があります。MongoDBを使用してはならない理由
Omid

138

mongodbクライアントコンソールを使用して、数行で簡単な関数を使用して、1つのコレクション内のすべてのデータをマージ/結合できます。これで、目的のクエリを実行できます。完全な例の下に、

.-著者:

db.authors.insert([
    {
        _id: 'a1',
        name: { first: 'orlando', last: 'becerra' },
        age: 27
    },
    {
        _id: 'a2',
        name: { first: 'mayra', last: 'sanchez' },
        age: 21
    }
]);

.-カテゴリ:

db.categories.insert([
    {
        _id: 'c1',
        name: 'sci-fi'
    },
    {
        _id: 'c2',
        name: 'romance'
    }
]);

.-本

db.books.insert([
    {
        _id: 'b1',
        name: 'Groovy Book',
        category: 'c1',
        authors: ['a1']
    },
    {
        _id: 'b2',
        name: 'Java Book',
        category: 'c2',
        authors: ['a1','a2']
    },
]);

.-貸出

db.lendings.insert([
    {
        _id: 'l1',
        book: 'b1',
        date: new Date('01/01/11'),
        lendingBy: 'jose'
    },
    {
        _id: 'l2',
        book: 'b1',
        date: new Date('02/02/12'),
        lendingBy: 'maria'
    }
]);

.-魔法:

db.books.find().forEach(
    function (newBook) {
        newBook.category = db.categories.findOne( { "_id": newBook.category } );
        newBook.lendings = db.lendings.find( { "book": newBook._id  } ).toArray();
        newBook.authors = db.authors.find( { "_id": { $in: newBook.authors }  } ).toArray();
        db.booksReloaded.insert(newBook);
    }
);

.-新しいコレクションデータを取得します。

db.booksReloaded.find().pretty()

.-応答:)

{
    "_id" : "b1",
    "name" : "Groovy Book",
    "category" : {
        "_id" : "c1",
        "name" : "sci-fi"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        }
    ],
    "lendings" : [
        {
            "_id" : "l1",
            "book" : "b1",
            "date" : ISODate("2011-01-01T00:00:00Z"),
            "lendingBy" : "jose"
        },
        {
            "_id" : "l2",
            "book" : "b1",
            "date" : ISODate("2012-02-02T00:00:00Z"),
            "lendingBy" : "maria"
        }
    ]
}
{
    "_id" : "b2",
    "name" : "Java Book",
    "category" : {
        "_id" : "c2",
        "name" : "romance"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        },
        {
            "_id" : "a2",
            "name" : {
                "first" : "mayra",
                "last" : "sanchez"
            },
            "age" : 21
        }
    ],
    "lendings" : [ ]
}

この行がお役に立てば幸いです。


2
doctrine mongodbを使用してこの同じコードを実行できるかどうか疑問に思っていますか?
14年

4
参照オブジェクトの1つが更新されるとどうなりますか?その更新は自動的に本オブジェクトに反映されますか?または、そのループを再度実行する必要がありますか?
バラプトン2014年

14
データが小さい限り、これで問題ありません。それはあなたのクライアントにそれぞれの本の内容を持って行き、それからそれぞれのカテゴリー、貸出そして著者を一つずつフェッチします。あなたの本が数千に達すると、これは本当に非常に遅くなります。より良い手法は、おそらく集約パイプラインを使用して、マージされたデータを別のコレクションに出力することです。もう一度お話ししましょう。その答えを追加します。
Sandeep Giri

アルゴリズムをこの他の例に適応できますか?stackoverflow.com/q/32718079/287948
Peter Krauss

1
@SandeepGiri分離されたコレクションに本当に集中的なデータがあるので、集約パイプラインをどのように実行できますか?
Yassine Abdul-Rahman

38

あなたはあなたが説明した方法でそれをしなければなりません。MongoDBは非リレーショナルデータベースであり、結合をサポートしていません。


4
SQLサーバーのバックグラウンドから来る賢いパフォーマンスは間違っているようですが、おそらくドキュメントデータベースではそれほど悪くないのですか?
terjetyl 2010

3
同様に、SQLサーバーの背景から、私はMongoDBのがはるかにSQLでのネストされたクエリのように、一度に新しいクエリの入力として(選択返されるフィールドで)「結果セット」を取っていただければ幸いです
Stijnサンダース

1
@terjetyl本当に計画する必要があります。フロントエンドに表示するフィールドはどれですか。個々のビューで制限されている場合は、それらを埋め込みドキュメントとして扱います。重要なのは、結合を行う必要がないことです。詳細な分析を行う場合は、別のデータベースで事後に分析します。最適なパフォーマンスを得るために、データをOL​​APキューブに変換するジョブを実行します。
Snowburnt 2013年

4
mongo 3.2バージョンから、左結合がサポートされています。
Somnath Muluk、2015年

18

他の人が指摘しているように、本当にしたくないリレーショナルデータベースからリレーショナルデータベースを作成しようとしていますが、とにかく、これを実行する必要がある場合は、ここで使用できるソリューションです。まずコレクションA(またはユーザーの場合はユーザー)でforeach検索を実行し、次に各アイテムをオブジェクトとして取得してから、オブジェクトプロパティ(ユーザーの場合はuid)を使用して、2番目のコレクション(ユーザーの場合はコメント)を検索します。それを見つけることができれば、マッチができ、それを印刷したり何かをしたりできます これがあなたと幸運を助けることを願っています:)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});

これで、現在ループしているアイテムが見つかりませんか?
Skarlinski 2017年

18

$ lookup$ project、および$ matchの適切な組み合わせにより、複数のパラメーターで複数のテーブルを結合できます。これは、それらを複数回チェーンできるためです。

次のようにしたいとします(参照

SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND 
S.MOB IS NOT NULL

ステップ1:すべてのテーブルをリンクする

あなたは好きなだけテーブルを$ lookupできます。

$ lookup-クエリのテーブルごとに1つ

$ unwind-データが正しく非正規化されるため、それ以外の場合は配列にラップされます

Pythonコード

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"}

                        ])

ステップ2:すべての条件を定義する

$ project:ここですべての条件ステートメントと、選択するすべての変数を定義します。

Pythonコード...

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }}
                        ])

ステップ3:すべての条件を結合する

$ match -ORまたはANDなどを使用してすべての条件を結合します。これらの条件が複数ある場合があります。

$ project:すべての条件を定義解除

Pythonコード...

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "$R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }},

                        # join all conditionals

                        {"$match": {
                          "$and": [
                            {"R.TIM": {"$gt": 0}}, 
                            {"MOB": {"$exists": True}},
                            {"midEq": {"$eq": True}}
                        ]}},

                        # undefine conditionals

                        {"$project": {
                          "midEq": 0
                        }}

                        ])

この方法で、テーブル、条件、結合のほとんどすべての組み合わせを実行できます。


17

これは「結合」 * Actors and Moviesコレクションの例です。

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

.mapReduce()メソッドを利用する

*結合 -ドキュメント指向データベースでの結合の代替手段


19
-1、これは2つのコレクションのデータを結合しません。データをピボットする単一のコレクション(俳優)からのデータを使用しています。キーだったものが値になり、値がキーになりました... JOINとは非常に異なります。
エヴァンテラン

12
これはまさにあなたがしなければならないことです。MongoDBはリレーショナルではなく、ドキュメント指向です。MapReduceを使用すると、大きなパフォーマンスでデータを操作できます(クラスターなどを使用できます...)が、単純なケースでも非常に便利です。
Thomas Decaux

14

3.2バージョンで提供されているlookupを使用して、Mongoの2つのコレクションに参加できます。あなたの場合、クエリは

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

または、ユーザーに関して参加することもできます。その場合、以下に示すように少し変更されます。

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

SQLの左および右結合と同じように機能します。


11

それはあなたが何をしようとしているのかに依存します。

現在、それを正規化されたデータベースとして設定していますが、これは問題なく、その方法は適切です。

ただし、他にも方法があります。

反復的に取得できるユーザーへの参照を含む各投稿のコメントを埋め込んだ投稿コレクションを作成できます。コメント付きのユーザー名を保存したり、それらすべてを1つのドキュメントに保存したりできます。

NoSQLの重要な点は、柔軟なスキーマと非常に高速な読み取りと書き込みのために設計されていることです。典型的なビッグデータファームでは、データベースが最大のボトルネックであり、アプリケーションやフロントエンドサーバーよりもデータベースエンジンの数が少ないです。それらはより高価ですが、より強力であり、ハードドライブの容量も比較的安価です。正規化はスペースを節約しようとするという概念から来ていますが、データベースに複雑な結合を実行させ、関係の整合性を検証し、カスケード操作を実行するコストが伴います。データベースを適切に設計すれば、開発者はすべて頭痛の種を省くことができます。

NoSQLでは、冗長性とストレージスペースのコスト(更新の実行に必要なプロセッサ時間と追加データを格納するためのハードドライブのコストの両方)が問題にならないことを受け入れる場合、非正規化は問題になりません(組み込みアレイの場合)何十万ものアイテムはパフォーマンスの問題になる可能性がありますが、ほとんどの場合それは問題ではありません)。さらに、すべてのデータベースクラスターに複数のアプリケーションサーバーとフロントエンドサーバーがあります。結合の重い処理を実行して、データベースサーバーが読み取りと書き込みに固執するようにします。

TL; DR:あなたがやっていることは結構です、そしてそれを行う他の方法があります。mongodbドキュメンテーションのデータモデルパターンで、優れた例を確認してください。http://docs.mongodb.org/manual/data-modeling/


8
「正規化は、スペースを節約しようとするという概念から生まれます」私はこれに疑問を投げかけます。IMHOの正規化は、冗長性を回避するという概念に基づいています。ユーザーの名前をブログ投稿と共に保存するとします。彼女が結婚したらどうなりますか?正規化されていないモデルでは、すべての投稿を調べて名前を変更する必要があります。正規化されたモデルでは、通常1つのレコードを変更します。
DanielKhan 2013年

@DanielKhanによる冗長性の防止とスペースの節約は同様の概念ですが、再分析の結果、冗長性がこの設計の根本的な原因であることに同意します。言い直します。メモありがとうございます。
Snowburnt 2013年

11

DBRefと呼ばれる多くのドライバーがサポートする仕様があります。

DBRefは、ドキュメント間の参照を作成するためのより正式な仕様です。DBRefには、(通常)コレクション名とオブジェクトIDが含まれます。ほとんどの開発者は、コレクションがドキュメント間で変更される可能性がある場合にのみDBRefを使用します。参照されるコレクションが常に同じである場合、上で概説した手動の参照の方が効率的です。

MongoDBドキュメントから引用:データモデル>データモデルリファレンス> データベースリファレンス


11

$ lookup(集計)

同じデータベース内のシャーディングされていないコレクションに対して左外部結合を実行して、処理のために「結合された」コレクションからドキュメントをフィルターに掛けます。$ lookupステージは、各入力ドキュメントに、「結合された」コレクションからの一致するドキュメントを要素とする新しい配列フィールドを追加します。$ lookupステージは、これらの再形成されたドキュメントを次のステージに渡します。$ lookupステージの構文は次のとおりです。

平等マッチ

入力ドキュメントのフィールドと「結合された」コレクションのドキュメントのフィールドとの間で等価一致を実行するために、$ lookupステージの構文は次のとおりです。

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

操作は次の疑似SQLステートメントに対応します。

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

Mongo URL


サブクエリは結合とはまったく異なります。左側のテーブルが巨大な場合、サブクエリは各行がクエリ自体を実行する必要があることを意味します。非常に遅くなります。SQLでの結合は非常に高速です。
yww325

8

3.2.6より前のバージョンでは、Mongodbはmysqlのような結合クエリをサポートしていません。あなたのために働くソリューションの下。

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])


3

MongoDBは結合を許可していませんが、プラグインを使用してそれを処理できます。mongo-joinプラグインを確認してください。それは最高で、私はすでにそれを使用しました。このようにnpmを使用して直接インストールできnpm install mongo-joinます。完全なドキュメントと例を確認できます。

(++)(N)コレクションに参加する必要があるときに本当に役立つツール

(-)クエリの最上位にのみ条件を適用できます

var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
    Database.collection('Appoint', function (err, Appoints) {

        /* we can put conditions just on the top level */
        Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
            full_date :{ $lte: end_date }}, function (err, cursor) {
            var join = new Join(Database).on({
                field: '_id_Doctor', // <- field in Appoints document
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            }).on({
                field: '_id_Patient', // <- field in Appoints doc
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            })
            join.toArray(cursor, function (err, joinedDocs) {

                /* do what ever you want here */
                /* you can fetch the table and apply your own conditions */
                .....
                .....
                .....


                resp.status(200);
                resp.json({
                    "status": 200,
                    "message": "success",
                    "Appoints_Range": joinedDocs,


                });
                return resp;


            });

    });

2

集約パイプラインを使用してそれを行うことができますが、それを自分で書くのは面倒です。

使用できます mongo-join-queryして、クエリから自動的に集計パイプラインを作成ます。

クエリは次のようになります。

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Comment,
    {
        find: { pid:444 },
        populate: ["uid"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

結果のuidフィールドにはユーザーオブジェクトが含まれ、必要なだけ深いレベルにリンクできます。ユーザーへの参照を入力して、チームへの参照を作成したり、他の何かへの参照を作成したりできます。

免責事項:私はmongo-join-queryこの正確な問題に取り組むために書いた。


0

playORMは、パーティション内で結合を実行できるようにパーティションを追加するだけのS-SQL(Scalable SQL)を使用してそれを実行できます。


-2

いいえ、間違っているようには見えません。MongoDBの参加は「クライアント側」です。あなたが言ったように:

現時点では、まず自分の基準に一致するコメントを取得してから、その結果セット内のすべてのuidを把握し、ユーザーオブジェクトを取得して、コメントの結果とマージしています。私はそれを間違っているようです。

1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.

これは「実際の」結合ではありませんが、「多くの」サイド結合の重複行を処理する必要がないため、SQL結合よりもはるかに便利です。代わりに、最初に選択したセットを装飾します。

このページには多くのナンセンスとFUDがあります。5年後、MongoDBがまだ存在していることが判明しました。


「「多」側結合の重複行を処理する必要はありません」 -これが何を意味するのかわからない。明確にできますか?
Mark Amery

1
@MarkAmery、確かに。SQLでは、nn関係は重複する行を返します。例えば友達。ボブがメアリーとジェーンと友達である場合、ボブの2行(ボブ、メアリー、ボブ、ジェーン)が表示されます。2ボブは嘘です。ボブは1人だけです。クライアント側の結合を使用すると、ボブから始めて、好きなように装飾できます:ボブ、「メアリーとジェーン」。SQLを使用すると、サブクエリを使用してこれを実行できますが、これは、クライアントで実行できる作業をdbサーバーで実行しています。
マイケルコール

-3

正規化されたデータテーブルが必要な場合-他のデータベースソリューションを試す必要があると思います。

しかし、私はGitでのMOngoの解決策を見つけました。 ちなみに、挿入コードには、映画の名前がありますが、noi映画のIDがあります

問題

あなたは彼らがやった映画の配列を持つ俳優のコレクションを持っています。

それぞれにアクターの配列を含む映画のコレクションを生成します。

いくつかのサンプルデータ

 db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
 db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

解決

アクタードキュメントの各ムービーをループして、各ムービーを個別に出力する必要があります。

ここでの問題は、削減フェーズです。縮小フェーズから配列を生成することはできないため、返される「値」ドキュメント内にActors配列を作成する必要があります。

コード
map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}

reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

actor_listが実際には配列を含むJavaScriptオブジェクトであることに注意してください。また、マップが同じ構造を放出することにも注意してください。

次のコマンドを実行してmap / reduceを実行し、「pivot」コレクションに出力して結果を出力します。

printjson(db.actors.mapReduce(map、reduce、 "pivot")); db.pivot.find()。forEach(printjson);

これはサンプル出力です。「Pretty Woman」と「Runaway Bride」には「Richard Gere」と「Julia Roberts」の両方があることに注意してください。

{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }


この回答のほとんどの内容(つまり、わかりやすい英語のビット)は、回答者が提供したGitHubリンクのMongoDBクックブックからコピーされています。
Mark Amery

-4

mongoDBサブクエリを使用して、2つのコレクションをマージできます。これが例ですコメント

`db.commentss.insert([
  { uid:12345, pid:444, comment:"blah" },
  { uid:12345, pid:888, comment:"asdf" },
  { uid:99999, pid:444, comment:"qwer" }])`

ユーザー-

db.userss.insert([
  { uid:12345, name:"john" },
  { uid:99999, name:"mia"  }])

JOINのMongoDBサブクエリ-

`db.commentss.find().forEach(
    function (newComments) {
        newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
        db.newCommentUsers.insert(newComments);
    }
);`

新しく生成されたコレクションから結果を取得します-

db.newCommentUsers.find().pretty()

結果 -

`{
    "_id" : ObjectId("5511236e29709afa03f226ef"),
    "uid" : 12345,
    "pid" : 444,
    "comment" : "blah",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f0"),
    "uid" : 12345,
    "pid" : 888,
    "comment" : "asdf",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f1"),
    "uid" : 99999,
    "pid" : 444,
    "comment" : "qwer",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f3"),
            "uid" : 99999,
            "name" : "mia"
        }
    ]
}`

これが役立つことを願っています。


7
基本的に、このほぼ同一の1年前の回答を基本的にコピーしたのはなぜですか。 stackoverflow.com/a/22739813/4186945
ハッケル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.