Bagaimana saya melakukan yang setara SQL Join di MongoDB?

498

Bagaimana saya melakukan yang setara SQL Join di MongoDB?

Misalnya, Anda memiliki dua koleksi (pengguna dan komentar) dan saya ingin menarik semua komentar dengan pid = 444 bersama dengan info pengguna untuk masing-masing.

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

Apakah ada cara untuk menarik semua komentar dengan bidang tertentu (mis. ... find ({pid: 444})) dan informasi pengguna yang terkait dengan setiap komentar dalam sekali jalan?

Saat ini, saya pertama-tama mendapatkan komentar yang sesuai dengan kriteria saya, kemudian mencari tahu semua uid di set hasil itu, mendapatkan objek pengguna, dan menggabungkannya dengan hasil komentar. Sepertinya saya salah melakukannya.

Yang tidak diketahui
sumber
35
Jawaban terakhir pada pertanyaan ini mungkin yang paling relevan, karena MongoDB 3.2+ menerapkan solusi gabungan yang disebut $ lookup. Kupikir aku akan mendorongnya ke sini karena mungkin tidak semua orang akan membaca sampai ke bawah. stackoverflow.com/a/33511166/2593330
thefourtheye
6
Benar, $ lookup diperkenalkan di MongoDB 3.2. Detail dapat ditemukan di docs.mongodb.org/master/reference/operator/aggregation/lookup/…
NDB

Jawaban:

306

Pada Mongo 3.2 jawaban untuk pertanyaan ini sebagian besar tidak lagi benar. Operator $ lookup baru yang ditambahkan ke pipa agregasi pada dasarnya identik dengan gabungan luar kiri:

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

Dari dokumen:

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

Tentu saja Mongo bukan database relasional, dan para pengembang sedang berhati-hati untuk merekomendasikan kasus penggunaan khusus untuk $ lookup, tetapi setidaknya pada 3.2 melakukan join sekarang dimungkinkan dengan MongoDB.

Clayton Gulick
sumber
@clayton: Bagaimana kalau lebih dari dua koleksi?
Dipen Dedania
1
@DipenDedania hanya menambahkan tahap pencarian $ tambahan ke pipa agregasi.
Clayton Gulick
Saya tidak dapat bergabung dengan bidang apa pun di array dalam koleksi kiri dengan id yang sesuai di kanan collection.can ada yang bisa membantu saya ??
Prateek Singh
1
Saya agak bingung tentang ini - apakah ada cara untuk menentukan bahwa Anda hanya menginginkan dokumen tertentu dalam koleksi "dari", atau apakah secara otomatis bergabung semua dalam db sekaligus?
user3413723
Hanya ingin tahu apakah Spring Data MongoDB terbaru memiliki dukungan untuk 3.2?
gtiwari333
142

Halaman ini di situs mongodb resmi menjawab persis pertanyaan ini:

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

Saat kami menampilkan daftar cerita kami, kami harus menunjukkan nama pengguna yang memposting cerita. Jika kami menggunakan basis data relasional, kami dapat melakukan gabungan pada pengguna dan toko, dan mendapatkan semua objek kami dalam satu permintaan. Tetapi MongoDB tidak mendukung bergabung dan karenanya, kadang-kadang, memerlukan sedikit denormalization. Di sini, ini berarti caching atribut 'nama pengguna'.

Puritan relasional mungkin sudah merasa tidak nyaman, seolah-olah kita melanggar beberapa hukum universal. Tapi mari kita ingat bahwa koleksi MongoDB tidak setara dengan tabel relasional; masing-masing melayani tujuan desain yang unik. Tabel yang dinormalisasi menyediakan potongan data atomik yang terisolasi. Namun, sebuah dokumen lebih dekat merepresentasikan objek secara keseluruhan. Dalam kasus situs berita sosial, dapat dikatakan bahwa nama pengguna adalah intrinsik dari cerita yang diposting.

William Stein
sumber
51
@dudelgrincen ini adalah perubahan paradigma dari normalisasi dan database relasional. Tujuan dari NoSQL adalah membaca dan menulis dari basis data dengan sangat cepat. Dengan BigData Anda akan memiliki aplikasi dan server front end dengan angka lebih rendah pada DB. Anda diharapkan melakukan jutaan transaksi setiap detik. Lepaskan beban berat dari database dan letakkan di level aplikasi. Jika Anda membutuhkan analisis mendalam, Anda menjalankan pekerjaan integrasi yang menempatkan data Anda ke dalam database OLAP. Anda seharusnya tidak mendapatkan banyak pertanyaan mendalam dari OLTP dbs Anda.
Snowburnt
18
@ Dudelgrincen Saya juga harus mengatakan bahwa itu bukan untuk setiap proyek atau desain. Jika Anda memiliki sesuatu yang berfungsi di database tipe SQL mengapa mengubahnya? Jika Anda tidak dapat memijat skema Anda untuk bekerja dengan noSQL, maka jangan.
Snowburnt
9
Migrasi dan skema yang terus berkembang juga jauh lebih mudah untuk dikelola pada sistem NoSQL.
justin
14
Bagaimana jika pengguna memiliki 3.540 posting di situs web, dan ia mengubah nama pengguna di profil? Haruskah setiap posting diperbarui dengan nama pengguna baru?
Ivo Pereira
2
@IvoPereira Ya dan itulah mengapa seseorang harus menghindari memodelkan data dengan cara ini. Ada sebuah artikel yang menjelaskan skenario yang sama dan konsekuensinya: Mengapa Anda Seharusnya Tidak Pernah Menggunakan MongoDB
Omid
138

Kami dapat menggabungkan / menggabungkan semua data hanya dalam satu koleksi dengan fungsi yang mudah dalam beberapa baris menggunakan konsol klien mongodb, dan sekarang kami dapat dapat melakukan permintaan yang diinginkan. Di bawah contoh lengkap,

.- Penulis:

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

.- Kategori:

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

.- Buku

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

.- Peminjaman buku

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'
    }
]);

.- Sihir:

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

.- Dapatkan data pengumpulan baru:

db.booksReloaded.find().pretty()

.- Respon :)

{
    "_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" : [ ]
}

Saya harap kalimat ini dapat membantu Anda.

Orlando Becerra
sumber
2
Saya ingin tahu apakah kode yang sama ini dapat dijalankan menggunakan doctrine mongodb?
abbood
4
Apa yang terjadi ketika salah satu objek referensi mendapat pembaruan? Apakah pembaruan itu secara otomatis tercermin dalam objek buku? Atau apakah loop itu perlu dijalankan lagi?
balupton
14
Ini bagus selama data Anda kecil. Ini akan membawa setiap konten buku ke klien Anda dan kemudian mengambil setiap kategori, pinjaman dan penulis satu per satu. Saat buku Anda mencapai ribuan, ini akan menjadi sangat lambat. Teknik yang lebih baik mungkin adalah dengan menggunakan pipa agregasi dan output data yang digabungkan ke dalam koleksi terpisah. Biarkan saya kembali lagi. Saya akan menambahkan jawaban itu.
Sandeep Giri
Bisakah Anda menyesuaikan algoritme Anda dengan contoh lain ini? stackoverflow.com/q/32718079/287948
Peter Krauss
1
@SandeepGiri bagaimana saya bisa melakukan pipa agregat karena saya punya data yang sangat sangat intensif dalam koleksi terpisah perlu bergabung ??
Yassine Abdul-Rahman
38

Anda harus melakukannya dengan cara yang Anda gambarkan. MongoDB adalah basis data non-relasional dan tidak mendukung gabungan.

Otto Allmendinger
sumber
4
Tampaknya kinerja yang salah berasal dari latar belakang sql server, tetapi mungkin tidak seburuk itu dengan dokumen db?
terjetyl
3
dari latar belakang sql server juga, saya akan sangat menghargai MongoDB mengambil 'set hasil' (dengan bidang yang dipilih kembali) sebagai input untuk permintaan baru dalam sekali jalan, mirip dengan permintaan bersarang di SQL
Stijn Sanders
1
@terjetyl Anda harus benar-benar merencanakannya. Bidang apa yang akan Anda presentasikan di ujung depan, jika jumlahnya terbatas dalam tampilan individual maka Anda menganggapnya sebagai dokumen yang disematkan. Kuncinya adalah tidak perlu melakukan join. Jika Anda ingin melakukan analisis mendalam, Anda melakukannya setelah fakta di database lain. Jalankan pekerjaan yang mengubah data menjadi kubus OLAP untuk kinerja yang optimal.
Snowburnt
4
Dari mongo versi 3.2 gabung kiri didukung.
Somnath Muluk
18

Seperti yang orang lain tunjukkan, Anda mencoba membuat database relasional dari tidak ada database relasional yang sebenarnya tidak ingin Anda lakukan selain itu, jika Anda memiliki kasus yang harus Anda lakukan di sini, ini adalah solusi yang dapat Anda gunakan. Kami pertama-tama melakukan pencarian foreach pada koleksi A (atau dalam kasus pengguna Anda) dan kemudian kami mendapatkan setiap item sebagai objek kemudian kami menggunakan properti objek (dalam kasus Anda) untuk mencari dalam koleksi kedua kami (dalam komentar kasus Anda) jika kami dapat menemukannya maka kami memiliki kecocokan dan kami dapat mencetak atau melakukan sesuatu dengannya. Semoga ini bisa membantu Anda dan semoga berhasil :)

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
    }
});
grepit
sumber
Tidakkah ini akan menemukan item yang sedang kita putar?
Skarlinski
18

Dengan kombinasi yang tepat dari $ lookup , $ project dan $ match , Anda dapat bergabung dengan tabel mutiple pada beberapa parameter. Ini karena mereka dapat dirantai beberapa kali.

Misalkan kita ingin melakukan hal berikut ( referensi )

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

Langkah 1: Tautkan semua tabel

Anda dapat $ mencari tabel sebanyak yang Anda inginkan.

$ lookup - satu untuk setiap tabel dalam kueri

$ melepas - karena data dinormalisasi dengan benar, kalau tidak dibungkus dalam array

Kode python ..

db.LeftTable.aggregate([
                        # connect all tables

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

                        ])

Langkah 2: Tentukan semua persyaratan

$ proyek : tentukan semua pernyataan kondisional di sini, ditambah semua variabel yang ingin Anda pilih.

Kode 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
                        }}
                        ])

Langkah 3: Bergabunglah dengan semua persyaratan

$ match - gabung semua ketentuan menggunakan ATAU DAN DAN dll. Ada beberapa hal berikut.

$ project : batalkan semua persyaratan

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

                        ])

Kombinasi tabel, kondisional, dan gabungan dapat dilakukan dengan cara ini.

sbharti
sumber
17

Berikut ini contoh koleksi "gabungan" * Aktor dan Film :

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

Itu menggunakan .mapReduce()metode

* bergabung - alternatif untuk bergabung dalam basis data berorientasi dokumen

bersifat antitoksin
sumber
19
-1, Ini BUKAN menggabungkan data dari dua koleksi. Itu menggunakan data dari satu koleksi (aktor) yang memutar data di sekitarnya. Sehingga hal-hal yang tadinya kunci sekarang nilai dan nilai sekarang kunci ... sangat berbeda dari BERGABUNG.
Evan Teran
12
Ini persis apa yang harus Anda lakukan, MongoDB bukan relasional tetapi berorientasi pada dokumen. MapReduce memungkinkan untuk bermain dengan data dengan kinerja besar (Anda dapat menggunakan cluster dll ....) tetapi bahkan untuk kasus sederhana, ini sangat berguna!
Thomas Decaux
14

Anda dapat bergabung dengan dua koleksi di Mongo dengan menggunakan pencarian yang ditawarkan dalam versi 3.2. Dalam kasus Anda, kueri akan menjadi

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

atau Anda juga dapat bergabung sehubungan dengan pengguna maka akan ada sedikit perubahan seperti yang diberikan di bawah ini.

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

Ini akan berfungsi sama seperti bergabung kiri dan kanan dalam SQL.

jafery jarry
sumber
11

Itu tergantung pada apa yang Anda coba lakukan.

Anda saat ini mengaturnya sebagai database yang dinormalisasi, yang baik-baik saja, dan cara Anda melakukannya sesuai.

Namun, ada cara lain untuk melakukannya.

Anda bisa memiliki koleksi posting yang telah menanamkan komentar untuk setiap posting dengan referensi ke pengguna yang Anda bisa dapatkan secara iteratif. Anda dapat menyimpan nama pengguna dengan komentar, Anda dapat menyimpan semuanya dalam satu dokumen.

Masalahnya dengan NoSQL adalah dirancang untuk skema fleksibel dan membaca dan menulis yang sangat cepat. Dalam sebuah peternakan Big Data khas, basis data adalah hambatan terbesar, Anda memiliki lebih sedikit mesin basis data daripada aplikasi dan server ujung depan ... mereka lebih mahal tetapi lebih kuat, juga ruang hard drive relatif murah. Normalisasi datang dari konsep mencoba menghemat ruang, tetapi ia datang dengan biaya untuk membuat database Anda berkinerja rumit. Bergabung dan memverifikasi integritas hubungan, melakukan operasi kaskade. Semua yang menyimpan sakit kepala pengembang jika mereka mendesain database dengan benar.

Dengan NoSQL, jika Anda menerima bahwa redundansi dan ruang penyimpanan tidak menjadi masalah karena biayanya (baik dalam waktu prosesor yang diperlukan untuk melakukan pembaruan dan biaya hard drive untuk menyimpan data tambahan), denormalisasi bukan merupakan masalah (untuk array tertanam yang menjadi ratusan ribu item itu bisa menjadi masalah kinerja, tetapi sebagian besar waktu itu bukan masalah). Selain itu, Anda akan memiliki beberapa aplikasi dan server ujung depan untuk setiap cluster basis data. Mintalah mereka melakukan angkat berat dari gabungan dan biarkan server database tetap membaca dan menulis.

TL; DR: Apa yang Anda lakukan baik-baik saja, dan ada cara lain untuk melakukannya. Lihat pola model data dokumentasi mongodb untuk beberapa contoh hebat. http://docs.mongodb.org/manual/data-modeling/

Snowburnt
sumber
8
"Normalisasi datang dari konsep mencoba menyelamatkan ruang" Aku mempertanyakan ini. Normalisasi IMHO berasal dari konsep menghindari redundansi. Katakanlah Anda menyimpan nama pengguna bersama dengan posting blog. Bagaimana jika dia menikah? Dalam model yang tidak dinormalisasi Anda harus mengarungi semua posting dan mengubah nama. Dalam model yang dinormalisasi Anda biasanya mengubah SATU catatan.
DanielKhan
@DanielKhan mencegah redundansi dan menghemat ruang adalah konsep yang serupa, tetapi pada analisis ulang saya setuju, redundansi adalah akar penyebab desain ini. Saya akan reword. Terima kasih atas catatannya.
Snowburnt
11

Ada spesifikasi yang didukung banyak driver yang disebut DBRef.

DBRef adalah spesifikasi yang lebih formal untuk membuat referensi antar dokumen. DBRefs (umumnya) menyertakan nama koleksi dan juga id objek. Sebagian besar pengembang hanya menggunakan DBRefs jika koleksi dapat berubah dari satu dokumen ke yang berikutnya. Jika koleksi Anda yang dirujuk akan selalu sama, referensi manual yang diuraikan di atas lebih efisien.

Diambil dari Dokumentasi MongoDB: Model Data> Referensi Model Data> Referensi Database

Acar
sumber
11

$ lookup (agregasi)

Melakukan gabungan luar kiri ke koleksi yang tidak di-shard di database yang sama untuk memfilter dalam dokumen dari koleksi "bergabung" untuk diproses. Untuk setiap dokumen input, tahap $ lookup menambahkan bidang array baru yang unsur-unsurnya adalah dokumen yang cocok dari koleksi "bergabung". Tahap $ lookup melewati dokumen-dokumen yang dibentuk kembali ini ke tahap berikutnya. Tahap $ lookup memiliki sintaks berikut:

Pencocokan Kesetaraan

Untuk melakukan kecocokan kesetaraan antara bidang dari dokumen input dengan bidang dari dokumen koleksi "gabungan", tahap $ lookup memiliki sintaks berikut:

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

Operasi akan sesuai dengan pernyataan pseudo-SQL berikut:

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

URL Mongo

Goutam
sumber
sub-kueri sama sekali berbeda dari gabung, jika tabel sebelah kiri Anda besar, sub-kueri berarti setiap baris harus melakukan kueri itu sendiri. itu akan menjadi sangat lambat. bergabung sangat cepat dalam sql.
yww325
8

Sebelum 3.2.6 , Mongodb tidak mendukung permintaan bergabung seperti mysql. solusi di bawah ini yang bekerja untuk Anda.

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

Anda dapat menjalankan query SQL termasuk bergabung di MongoDB dengan mongo_fdw dari Postgres.

metdos
sumber
3

MongoDB tidak mengizinkan bergabung, tetapi Anda bisa menggunakan plugin untuk mengatasinya. Periksa plugin mongo-gabung. Ini yang terbaik dan saya sudah menggunakannya. Anda dapat menginstalnya menggunakan npm secara langsung seperti ini npm install mongo-join. Anda dapat melihat dokumentasi lengkapnya dengan contoh .

(++) alat yang sangat membantu ketika kita perlu bergabung (N) koleksi

(-) kami dapat menerapkan kondisi hanya pada tingkat atas permintaan

Contoh

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;


            });

    });
Amine_Dev
sumber
2

Anda dapat melakukannya menggunakan pipa agregasi, tetapi sulit untuk menulisnya sendiri.

Anda dapat menggunakan mongo-join-queryuntuk membuat pipa agregasi secara otomatis dari permintaan Anda.

Seperti inilah tampilan kueri Anda:

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

Hasil Anda akan memiliki objek pengguna di uidbidang dan Anda dapat menautkan level sedalam yang Anda inginkan. Anda dapat mengisi referensi ke pengguna, yang membuat referensi ke Tim, yang membuat referensi ke sesuatu yang lain, dll.

Penafian : Saya menulis mongo-join-queryuntuk mengatasi masalah ini.

Marcelo Lazaroni
sumber
0

playORM dapat melakukannya untuk Anda menggunakan S-SQL (Scalable SQL) yang hanya menambahkan partisi sehingga Anda dapat melakukan penggabungan di dalam partisi.

Dean Hiller
sumber
-2

Tidak, sepertinya Anda tidak melakukan kesalahan. Gabungan MongoDB adalah "sisi klien". Seperti yang Anda katakan:

Saat ini, saya pertama-tama mendapatkan komentar yang sesuai dengan kriteria saya, kemudian mencari tahu semua uid di set hasil itu, mendapatkan objek pengguna, dan menggabungkannya dengan hasil komentar. Sepertinya saya salah melakukannya.

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.

Ini bukan "nyata" bergabung, tapi itu sebenarnya jauh lebih berguna daripada SQL bergabung karena Anda tidak harus berurusan dengan baris duplikat untuk "banyak" bergabung dengan sisi, sebagai gantinya Anda menghias set yang dipilih sebelumnya.

Ada banyak omong kosong dan FUD di halaman ini. Ternyata 5 tahun kemudian MongoDB masih menjadi masalah.

Michael Cole
sumber
'Anda tidak harus berurusan dengan duplikat baris untuk "banyak" bergabung dengan sisi' - tidak tahu apa yang Anda maksud dengan ini. Bisakah Anda mengklarifikasi?
Mark Amery
1
@MarkAmery, tentu saja. Dalam SQL, hubungan nn akan mengembalikan baris duplikat. Misalnya teman. Jika Bob berteman dengan Mary dan Jane, Anda akan mendapatkan 2 baris untuk Bob: Bob, Mary dan Bob, Jane. 2 Bobs adalah dusta, hanya ada satu Bob. Dengan bergabung di sisi klien, Anda dapat mulai dengan Bob dan menghias sesuka Anda: Bob, "Mary and Jane". SQL mari kita lakukan ini dengan subqueries, tapi itu bekerja di server db yang bisa dilakukan pada klien.
Michael Cole
-3

Saya pikir, jika Anda memerlukan tabel data yang dinormalisasi - Anda perlu mencoba beberapa solusi database lainnya.

Tapi saya sudah menyelesaikan solusi untuk MOngo di Git By the way, dalam kode sisipan - ia memiliki nama film, tetapi ID film noi .

Masalah

Anda memiliki koleksi Aktor dengan berbagai Film yang telah mereka lakukan.

Anda ingin menghasilkan koleksi Film dengan berbagai Aktor di masing-masing.

Beberapa sampel data

 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'] });

Larutan

Kita perlu mengulang setiap film dalam dokumen Aktor dan memancarkan setiap Film satu per satu.

Tangkapan di sini sedang dalam fase reduksi. Kami tidak dapat memancarkan array dari fase pengurangan, jadi kami harus membuat array Aktor di dalam dokumen "nilai" yang dikembalikan.

Kode
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;
}

Perhatikan bagaimana actor_list sebenarnya adalah objek javascript yang berisi larik. Perhatikan juga bahwa peta memancarkan struktur yang sama.

Jalankan yang berikut ini untuk menjalankan peta / kurangi, tampilkan ke koleksi "pivot" dan cetak hasilnya:

printjson (db.actors.mapReduce (peta, kurangi, "pivot")); db.pivot.find (). forEach (printjson);

Berikut adalah contoh output, perhatikan bahwa "Pretty Woman" dan "Runaway Bride" memiliki "Richard Gere" dan "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" ] } }

Max Sherbakov
sumber
Perhatikan bahwa sebagian besar konten jawaban ini (yaitu bit yang dalam bahasa Inggris yang dapat dipahami) disalin dari buku masak MongoDB di tautan GitHub yang disediakan penjawab.
Mark Amery
-4

Kami dapat menggabungkan dua koleksi dengan menggunakan kueri mongoDB. Berikut ini contohnya, Komentar -

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

Userss--

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

Sub-permintaan MongoDB untuk JOIN--

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

Dapatkan hasil dari Collection-- yang baru dibuat

db.newCommentUsers.find().pretty()

Hasil--

`{
    "_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"
        }
    ]
}`

Semoga ini bisa membantu.

Krishna
sumber
7
Mengapa pada dasarnya Anda menyalin jawaban yang hampir sama, berumur satu tahun ini? stackoverflow.com/a/22739813/4186945
hackel