mongoDB: Aggregation - 是不是有相当于原生 node.js 驱动程序的 $lookup 连接?

Posted

技术标签:

【中文标题】mongoDB: Aggregation - 是不是有相当于原生 node.js 驱动程序的 $lookup 连接?【英文标题】:mongoDB: Aggregation - Is there a equivalent of the $lookup joins for the native node.js driver?mongoDB: Aggregation - 是否有相当于原生 node.js 驱动程序的 $lookup 连接? 【发布时间】:2016-02-05 20:30:35 【问题描述】:

mongodb: 2.1.3

在阅读了一些关于 mongoDB 3.2 的 aggregation enhancements 之后,我对“$look”管道阶段进行左外等连接感到兴奋。

不幸的是,节点驱动程序似乎没有此运算符。(我在native driver docs for node 中没有看到它,当我尝试使用它时出现错误:

更新:这是我尝试过的代码

var cursor = db.collection('messagethreads').aggregate([
        "$match": 
            _id: new ObjectID(threadID)
        , 
        "$lookup": 
            from: "messages", 
            localField: "_id",
            foreignField: "threadID",
            as: "messagesList"
        
    ]);

    cursor.toArray(function(err,messages)
        if(err) 
            res.status(500).json(error);
        
        else if(convo === null)
            res.status(400).end();
        
        else
            res.status(200).json(messages);
        
    );
);

示例 - 一个 ThreadMessage 文档

 
    "_id" : ObjectId("56b4f52c0e6368c00630aee6"), 
    name: "Messages 1"

示例 - 消息文档


     "_id" : ObjectId("56b4f52c0e6368c00630af08"), 
     "author" : "Nick", 
     "text" : "Hello", 
     "threadID" : ObjectId("56b4f52c0e6368c00630aee6")
,
...

预期结果


    "_id" : ObjectId("56b4f52c0e6368c00630aee6"), 
    name: "Messages 1",
    messageList:[
        
         "_id" : ObjectId("56b4f52c0e6368c00630af08"), 
         "author" : "Nick", 
         "text" : "Hello", 
         "threadID" : ObjectId("56b4f52c0e6368c00630aee6")
        ,
        ...
    ]

" MongoError: 异常:无法识别的管道阶段名称:'$lookup'"

您可以阅读更多关于连接案例here!

问题:是否有预期的方式来执行与 node.js 原生驱动程序等效的操作?

【问题讨论】:

驱动与此无关。聚合管道只是发送到服务器的序列化数据,没有任何解释(除了原生数据格式到 BSON 的转换),所以没有什么可以支持的。只要您的服务器版本支持该操作(MongoDB 3.2 或更高版本),那么您发送到服务器的内容就会被执行。 @BlakesSeven 我不明白 - 节点驱动程序的最新版本是 2.1.6 npmjs.com/package/mongodb 。我以为它会具有核心的所有功能,但是当我尝试时失败了并且节点本机驱动程序的文档确实显示 $limit 是聚合游标方法之一。 “驱动程序与此无关”的哪一部分如此难以理解? “驱动程序”实现的唯一东西是.aggregate() 方法(实际上是作为执行聚合的数据库命令的包装器)。管道的内容,就像任何查询一样,只是“内容”。 “驱动程序”除了发送它之外没有什么可以做的。驱动程序文档中没有查询或聚合运算符,除非有不支持动态结构分配的语言的“帮助”方法。 javascript 可以。 @BlakesSeven 很酷,谢谢。只是驱动程序实现和核心之间的一些语法细微差别 - 我认为我的错误可能是由简单的语法调整引起的。 存在“零”语法差异。在所有驱动程序实现中,“管道”始终是对象的“列表/数组”参数。但是,如果您在谈论您无法解决的代码中的“错误”,那么您的问题应该显示“不适合您”的代码,而不是“正在工作”的代码并询问 “我该怎么做做同样的事情吗?”。如果它不起作用,那么显然你没有做同样的事情。 【参考方案1】:

“MongoError”异常是驱动程序如何从“服务器”报告任何错误消息,因此这种错误表明连接到的服务器不是支持$lookup的版本,为3.2或更高:

$lookup

3.2 版中的新功能。

对同一数据库中的未分片集合执行左外连接,以过滤来自“已连接”集合的文档以进行处理。 $lookup 阶段在输入文档中的字段与“加入”集合的文档中的字段之间进行相等匹配。

您始终可以通过serverStatus 数据库命令获取您要连接的服务器版本。也在完全可复制的列表中:

var async = require('async'),
    mongodb = require('mongodb'),
    MongoClient = mongodb.MongoClient,
    ObjectId = mongodb.ObjectId;

MongoClient.connect("mongodb://localhost/test",function(err,db) 

  async.series(
    [
      function(callback) 
        db.command( "serverStatus": 1 , function(err,status) 
          console.log(status.version);
          callback(err);
        );
      ,
      function(callback) 
        async.each(['threadmessage','message'],function(colname,callback) 
          db.collection(colname).remove(,callback);
        ,callback);
      ,

      function(callback) 
        db.collection('threadmessage').insert(
          
            "_id" : ObjectId("56b4f52c0e6368c00630aee6"),
            "name": "Messages 1"
          ,
          callback
        );
      ,

      function(callback) 
        db.collection('message').insert(
          
            "_id" : ObjectId("56b4f52c0e6368c00630af08"),
            "author" : "Nick",
            "text" : "Hello",
            "threadID" : ObjectId("56b4f52c0e6368c00630aee6")
          ,
          callback
        );
      ,

      function(callback) 

        var cursor = db.collection('threadmessage').aggregate([
           "$lookup": 
            "from": "message",
            "localField": "_id",
            "foreignField": "threadID",
            "as": "messagesList"
          
        ]);

        cursor.toArray(function(err,result) 
          console.log(JSON.stringify(result,undefined,2));
          callback(err);
        );
      
    ],
    function(err) 
      if (err) throw err;
      db.close();
    
  );

);

以及固定驱动程序版本的 package.json,只是为了表明没有驱动程序版本问题:


  "name": "lookup",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": 
    "test": "echo \"Error: no test specified\" && exit 1"
  ,
  "author": "",
  "license": "ISC",
  "dependencies": 
    "async": "^1.5.2",
    "mongodb": "2.1.3"
  

使用受支持的服务器版本提供预期输出:

3.2.0
[
  
    "_id": "56b4f52c0e6368c00630aee6",
    "name": "Messages 1",
    "messagesList": [
      
        "_id": "56b4f52c0e6368c00630af08",
        "author": "Nick",
        "text": "Hello",
        "threadID": "56b4f52c0e6368c00630aee6"
      
    ]
  
]

因此,如果该列表未在您连接到的数据库上返回 3.2.x,则此处不支持 $lookup 管道操作,您将不得不求助于其他方法,例如拉入“相关”信息“客户端”。

【讨论】:

天哪!刚刚“咔嚓”一声! “服务器”这个词让我很反感,因为我想到了网络服务器。一旦人们安装了 mongoDB,它就像“我的数据库在那里”,我们不认为它是一个服务器。哈哈,我真的必须听起来像一个完整的菜鸟。我检查了一下,即使我有一个 3.2.x 的 GUI,实际服务器是 3.0.8 你是冠军!谢谢一百万!!

以上是关于mongoDB: Aggregation - 是不是有相当于原生 node.js 驱动程序的 $lookup 连接?的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB Aggregation - $unwind order 文档是不是与嵌套数组 order 相同

MongoDB Aggregation

mongodb Aggregation聚合操作之$sort

MongoDB 聚合管道(Aggregation Pipeline)

mongodb Aggregation聚合操作之$bucket

mongodb Aggregation聚合操作之$facet