如何在 MongoDB 中执行等效的 SQL Join?

Posted

技术标签:

【中文标题】如何在 MongoDB 中执行等效的 SQL Join?【英文标题】:How do I perform the SQL Join equivalent in MongoDB? 【发布时间】:2011-01-21 23:18:52 【问题描述】:

例如,假设您有两个集合(用户和 cmets),我想提取所有 pid=444 的 cmets 以及每个集合的用户信息。

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"  

有没有办法一次性提取具有某个字段的所有 cmets(例如 ...find(pid:444) )以及与每个评论关联的用户信息?

目前,我首先获取符合我的条件的 cmets,然后找出该结果集中的所有 uid,获取用户对象,并将它们与评论的结果合并。好像我做错了。

【问题讨论】:

关于这个问题的最后一个答案可能是最相关的,因为 MongoDB 3.2+ 实现了一个名为 $lookup 的连接解决方​​案。以为我会把它推到这里,因为也许不是每个人都会读到底。 ***.com/a/33511166/2593330 正确,$lookup 是在 MongoDB 3.2 中引入的。详情请见docs.mongodb.org/master/reference/operator/aggregation/lookup/… 将任何查询转换为mongo,查看答案:***.com/questions/68155715/… 【参考方案1】:

您必须按照您描述的方式进行操作。 MongoDB 是一个非关系型数据库,不支持连接。

【讨论】:

从 sql server 后台看来性能错误,但使用文档数据库可能还不错? 同样来自 sql server 背景,我希望 MongoDB 一次性将“结果集”(带有选定的返回字段)作为新查询的输入,就像 SQL 中的嵌套查询一样跨度> @terjetyl 你必须真正计划好。您将在前端显示哪些字段,如果在单个视图中数量有限,那么您将这些字段视为嵌入式文档。关键是不需要做连接。如果您想进行深入分析,请事后在另一个数据库中进行。运行将数据转换为 OLAP 多维数据集以获得最佳性能的作业。 从 mongo 3.2 版本开始支持左连接。【参考方案2】:

有一个被许多驱动程序支持的规范称为 DBRef。

DBRef 是用于在文档之间创建引用的更正式的规范。 DBRefs(通常)包括一个集合名称和一个对象 ID。大多数开发人员仅在集合可以从一个文档更改为下一个文档时才使用 DBRefs。如果您引用的集合始终相同,则上述手动引用会更有效。

取自 MongoDB 文档:数据模型 > 数据模型参考 > Database References

【讨论】:

【参考方案3】:

mongodb 官方网站上的这个页面正好解决了这个问题:

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

当我们显示故事列表时,我们需要显示发布故事的用户的姓名。如果我们使用关系数据库,我们可以对用户和存储执行连接,并在单个查询中获取所有对象。但是 MongoDB 不支持连接,因此有时需要一些非规范化。在这里,这意味着缓存“用户名”属性。

关系纯粹主义者可能已经感到不安,就好像我们违反了某些普遍规律一样。但请记住,MongoDB 集合并不等同于关系表;每个都有一个独特的设计目标。规范化表提供了一个原子的、隔离的数据块。然而,一个文档更接近地代表了一个整体的对象。在社交新闻网站的情况下,可以说用户名是发布的故事所固有的。

【讨论】:

@dudelgrincen 这是从规范化和关系数据库的范式转变。 NoSQL 的目标是非常快速地读取和写入数据库。使用 BigData,您将拥有大量应用程序和前端服务器,其 DB 数量较少。您需要每秒进行数百万笔交易。从数据库中卸载繁重的工作并将其放到应用程序级别。如果您需要深入分析,您可以运行将数据放入 OLAP 数据库的集成作业。无论如何,您不应该从您的 OLTP 数据库中获得很多深度查询。 @dudelgrincen 我还应该说它并不适用于每个项目或设计。如果您有在 SQL 类型数据库中工作的东西,为什么要更改它?如果你不能通过调整你的模式来使用 noSQL,那就不要。 迁移和不断发展的模式在 NoSQL 系统上也更容易管理。 如果用户在网站上有 3.540 个帖子,并且他确实更改了个人资料中的用户名怎么办?是否应该使用新用户名更新每个帖子? @IvoPereira 是的,这正是人们应该避免以这种方式建模数据的原因。有一篇文章解释了相同的场景及其后果:Why You Should Never Use MongoDB【参考方案4】:

这是一个“加入” * ActorsMovies 集合的示例:

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

它利用.mapReduce()方法

* join - 加入面向文档的数据库的替代方法

【讨论】:

-1,这不是连接来自两个集合的数据。它使用来自单个集合(参与者)的数据来旋转数据。所以以前是键的东西现在是值,而值现在是键...非常与 JOIN 不同。 这正是您必须做的,MongoDB 不是关系型的,而是面向文档的。 MapReduce 允许处理具有高性能的数据(您可以使用集群等......)但即使对于简单的情况,它也非常有用!【参考方案5】:

playORM 可以使用 S-SQL(Scalable SQL)为您完成此操作,它只是添加了分区,以便您可以在分区内进行连接。

【讨论】:

【参考方案6】:

您可以使用来自 Postgres 的 mongo_fdw 在 MongoDB 上运行 SQL 查询,包括连接。

【讨论】:

【参考方案7】:

这取决于你想要做什么。

您目前已将其设置为规范化数据库,这很好,而且您的操作方式也很合适。

但是,还有其他方法。

您可以拥有一个帖子集合,该集合为每个帖子嵌入了 cmets,其中包含对您可以迭代查询以获取的用户的引用。您可以将用户名与 cmets 一起存储,也可以将它们全部存储在一个文档中。

NoSQL 的特点是它专为灵活的模式和非常快速的读写而设计。在典型的大数据场中,数据库是最大的瓶颈,数据库引擎比应用程序和前端服务器少……它们更贵但更强大,硬盘空间也相对便宜。规范化来自试图节省空间的概念,但它会带来成本,使您的数据库执行复杂的联接和验证关系的完整性,执行级联操作。如果数据库设计得当,所有这些都可以为开发人员省去一些麻烦。

对于 NoSQL,如果您接受冗余和存储空间不是问题,因为它们的成本(更新所需的处理器时间和存储额外数据所需的硬盘成本),非规范化不是问题(对于嵌入式数组变成数十万个项目,这可能是一个性能问题,但大多数时候这不是问题)。此外,每个数据库集群都有多个应用程序和前端服务器。让他们完成连接的繁重工作,让数据库服务器坚持读写。

TL;DR:你正在做的很好,还有其他方法可以做到。查看 mongodb 文档的数据模型模式以获取一些很好的示例。 http://docs.mongodb.org/manual/data-modeling/

【讨论】:

“规范化来自试图节省空间的概念”我对此表示怀疑。恕我直言规范化来自避免冗余的概念。假设您将用户名与博文一起存储。如果她结婚了呢?在未标准化的模型中,您将不得不浏览所有帖子并更改名称。在标准化模型中,您通常会更改 ONE 记录。 @DanielKhan 防止冗余和节省空间是相似的概念,但经过重新分析,我同意,冗余是这种设计的根本原因。我会改写的。感谢您的来信。【参考方案8】:

我们可以使用 mongodb 客户端控制台在几行中通过简单的功能合并/连接仅一个集合中的所有数据,现在我们可以执行所需的查询。 下面是一个完整的例子,

.- 作者:

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

希望这几行能帮到你。

【讨论】:

我想知道是否可以使用学说 mongodb 运行相同的代码? 当引用对象之一获得更新时会发生什么?该更新是否会自动反映在 book 对象中?还是该循环需要再次运行? 这没问题,只要您的数据很小。它将把每本书的内容带给你的客户,然后逐一获取每个类别、借阅和作者。当你的书有成千上万的时候,这会真的很慢。更好的技术可能是使用聚合管道并将合并的数据输出到单独的集合中。让我再说一遍。我会添加一个答案。 你能把你的算法调整到另一个例子吗? ***.com/q/32718079/287948 @SandeepGiri 我该如何做聚合管道,因为我在分离的集合中有非常密集的数据需要加入??【参考方案9】:

我们可以使用 mongoDB 子查询合并两个集合。这是示例, 评论--

`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"
        
    ]
`

希望这会有所帮助。

【讨论】:

为什么您基本上复制了这个几乎相同的一年前的答案? ***.com/a/22739813/4186945【参考方案10】:

MongoDB 不允许连接,但您可以使用插件来处理它。检查 mongo-join 插件。这是最好的,我已经用过了。您可以像npm install mongo-join 一样直接使用 npm 安装它。您可以查看full documentation with examples。

(++) 当我们需要加入 (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;


            );

    );

【讨论】:

【参考方案11】:

正如其他人指出的那样,您正在尝试从您真的不想做的非关系数据库创建一个关系数据库,但无论如何,如果您有一个必须这样做的案例,这是一个您可以使用的解决方案.我们首先对集合 A(或在您的情况下为用户)进行 foreach 查找,然后我们将每个项目作为一个对象,然后我们使用对象属性(在您的情况下为 uid)在我们的第二个集合(在您的情况下为 cmets)中查找,如果我们可以找到它然后我们有一个匹配,我们可以打印或用它做一些事情。 希望这对你有帮助,祝你好运:)

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

【讨论】:

找不到我们当前正在循环播放的项目吗?【参考方案12】:

不,您似乎没有做错。 MongoDB 连接是“客户端”。和你说的差不多:

目前,我首先获取符合我的条件的 cmets,然后找出该结果集中的所有 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 仍然存在。

【讨论】:

'您不必处理“多”边连接的重复行' - 不知道您的意思。你能澄清一下吗? @MarkAmery,当然。在 SQL 中,n-n 关系将返回重复的行。例如。朋友们。如果 Bob 是 Mary 和 Jane 的朋友,您将得到 Bob 的 2 行:Bob,Mary 和 Bob,Jane。 2 Bobs 是个谎言,只有一个 Bob。通过客户端连接,您可以从 Bob 开始并按照您的喜好进行装饰:Bob,“Mary and Jane”。 SQL 让你用子查询来做这件事,但那是在 db 服务器上做的工作,可以在客户端上做。【参考方案13】:

我认为,如果您需要规范化的数据表 - 您需要尝试一些其他数据库解决方案。

但我在 Git 上找到了 Mongo 的解决方案 顺便说一句,在插入代码中 - 它有电影的名称,但 noi 电影的 ID

问题

您有一组 Actors 以及他们制作的一系列电影。

您想生成一个包含一组 Actor 的 Movies 集合。

一些样本数据

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

解决方案

我们需要遍历 Actor 文档中的每一部电影,并分别发出每一部影片。

这里的问题是在减少阶段。我们不能从 reduce 阶段发出一个数组,所以我们必须在返回的“值”文档中构建一个 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 发出相同的结构。

运行以下命令执行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" ]  

【讨论】:

请注意,此答案的大部分内容(即可理解的英语部分)是从 MongoDB 食谱中复制的,位于回答者提供的 GitHub 链接上。【参考方案14】:

从 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 进行连接。 p>

【讨论】:

@clayton : 多两个系列怎么样? @DipenDedania 只需向聚合管道添加额外的 $lookup 阶段。 我无法将左侧集合中的数组中的任何字段与右侧集合中的相应 id 连接起来。有人可以帮我吗?? 我对此有点困惑 - 有没有办法指定您只需要“来自”集合中的某些文档,或者它是否会一次自动加入数据库中的所有文档?跨度> 只是想知道最新的 Spring Data MongoDB 是否支持 3.2?【参考方案15】:

您可以使用 3.2 版本中提供的查找功能在 Mongo 中加入两个集合。在您的情况下,查询将是

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 中的左右连接相同。

【讨论】:

【参考方案16】:

3.2.6之前,Mongodb不像mysql那样支持join查询。以下解决方案适合您。

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

【讨论】:

【参考方案17】:

通过$lookup$project$match的正确组合,您可以在多个参数上连接多个表。这是因为它们可以被链接多次。

假设我们想要关注 (reference)

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 - 查询中的每个表一个

$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
                        

                        ])

几乎任何表格、条件和连接的组合都可以通过这种方式完成。

【讨论】:

谢谢!,喜欢你的回答格式。 完美答案,对我来说,"$unwind ":"R" 出现错误,如果将其更改为"$unwind":"$R",它就完美了!【参考方案18】:

您可以使用聚合管道来完成它,但是自己编写它很痛苦。

您可以使用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 来解决这个确切的问题。

【讨论】:

【参考方案19】:

$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

【讨论】:

子查询与join完全不同,如果你的左侧表很大,子查询意味着每一行都必须自己做一个查询。它会变得很慢。 join 在 sql 中非常快。

以上是关于如何在 MongoDB 中执行等效的 SQL Join?的主要内容,如果未能解决你的问题,请参考以下文章

等效的 MongoDB 语句?

MongoDB中SQL中减集操作的等效操作是啥?

春季是不是有 mongoDB 的 @MappedSuperclass 等效注释?

重复字符串上的 SQL 等效“$all”MongoDB 运算符

mongodb到sql的转换1

如何在 MongoDB 中执行此 Sql 查询