【问题标题】:Aggregation $lookup with $let is not working聚合 $lookup 与 $let 不起作用
【发布时间】:2018-10-08 19:31:10
【问题描述】:

我在 mongodb 中有一个集合 TblStudent,比如

       {
      "_id": ObjectId("5baa85041d7859f40d000029"),
       "Name": "John Doe",
       "RollNo": 12,
       "Class": "Ist"
        ....
       }

我还有一个收藏TblRoutelike

   {
   "_id": ObjectId("5baa818d1d78594010000029"),
   "Name": "New york City",
   "StopDetails": [
   {
    "StopId": "abc777",
    "Name": "Block no 3"
   },
   {
   "StopId": "abc888",
   "Name": "Block no 4"
   }
 ],
"NumberOfSeats": "10",
"StudentDetails": [
 {
   "StudentId": ObjectId("5baa85041d7859f40d000029"),
   "VehicleId": "7756"
  },
  {
   "StudentId": ObjectId("5baa85f61d7859401000002a"),
   "VehicleId": "7676"
 }
 ]
}

我使用的是 mongodb 3.6 平台。我正在使用下面的代码行

       $query = ['_id' => new MongoDB\BSON\ObjectID($this->id)];
    $cursor = $this->db->TblRoute->aggregate([
    ['$match' => $query],
    [
    '$lookup' =>
     [
       'from' => "TblStudent",
        'let' => ['StudentId' => '$StudentDetails.StudentId'],
        'pipeline' => [
          [ '$match' =>
             ['$expr' =>        
                ['$eq' => ['$StudentId',  '$$StudentId' ] ]  
             ]
          ],
           [ '$project' => ['Name' => 1, 'RollNo' => 1 ] ]
       ],
       'as' => "StudentDetails.StudentData"
     ]                   
    ] 
  ]);

我一直在尝试从另一个集合中获取数据,但仅包含某些字段。我正在尝试从 TblStudent 里面获取学生姓名和 RollNo 字段 TblRoute 是为了使文档数组轻量级。通常 $lookup 阶段会从另一个集合中获取所有字段。

我正在尝试上面的代码。它抛出错误消息

"StudentDetails.StudentData" is coming empty 'StudentDetails' => MongoDB\Model\BSONDocument::__set_state(array( 'StudentData' => MongoDB\Model\BSONArray::__set_state(array( )), )), 

但我认为代码编写不正确。实际方法可能不同。请帮我解决问题。

我希望输出类似于

{
"_id": ObjectId("5baa818d1d78594010000029"),
"Name": "New york City",
"StopDetails": [
     .....
  ],
   "StudentDetails": [
   {
   "StudentId": ObjectId("5baa85041d7859f40d000029"),
   "VehicleId": "7756",
   "StudentData": [
      "Name": ..
      "RollNo":...
    ]
    },
    {
    "StudentId": ObjectId("5baa85f61d7859401000002a"),
    "VehicleId": "7676",
     "StudentData": [
      "Name": ..
      "RollNo":...
    ]
   }
   ]
  }

【问题讨论】:

  • 错误信息是什么?
  • 致命错误:未捕获的异常 'MongoDB\Driver\Exception\RuntimeException' 带有消息 ''StudentId' 以用户变量名的无效字符开头
  • 好的,试试[ '$lookup' => [ 'from' => "TblStudent", 'let' => ['studentid' => '$StudentDetails.StudentId'], 'pipeline' => [ [ '$match' => ['$expr' => ['$in' => ['$StudentId', '$$studentid' ] ] ] ], [ '$project' => ['Name' => 1, 'RollNo' => 1 ] ] ], 'as' => "StudentDetails.StudentData" ]。来自文档 用户变量名称必须以小写 ascii 字母 [a-z] 或非 ascii 字符开头
  • 现在该错误消息消失了,但“StudentDetails.StudentData”为空 'StudentDetails' => MongoDB\Model\BSONDocument::__set_state(array( 'StudentData' => MongoDB\Model\BSONArray:: __set_state(array()), )),
  • 您在 $lookup 阶段是否使用了 $in 而不是 $eq ?

标签: mongodb aggregation-framework aggregate-functions mongodb-php php-mongodb


【解决方案1】:

使用以下聚合。

来自文档的注释

用户变量名称必须以小写 ascii 字母 [a-z] 或 一个非 ASCII 字符。

因此将$let 变量更改为studentid 并修复了代码中的其他问题。

db.TblRoute.aggregate([
  {"$match":ObjectId("5baa818d1d78594010000029")},
  {"$lookup":{
    "from":"TblStudent",
    "let":{"studentid":"$StudentDetails.StudentId"},
    "pipeline":[
      {"$match":{"$expr":{"$in":["$_id","$$studentid"]}}},
      {"$project":{"Name":1,"RollNo":1}}
    ],
    "as":"StudentDetails.StudentData"
  }}
])

【讨论】:

  • 很好的解决方案......谢谢......但它覆盖了以前的 StudentDetails。有没有其他方法可以避免这种覆盖...
  • 谢谢!很好的解决方案。完成了我的工作。
  • 这似乎不起作用,在新版本的 Mongo 中是否更改了语法?
  • 如果检查的不是StudentId,而是想用StudentData来检查呢?
猜你喜欢
  • 1970-01-01
  • 2021-12-01
  • 2018-12-20
  • 2020-07-12
  • 2020-08-07
  • 1970-01-01
  • 2021-04-11
  • 2022-01-05
  • 2021-06-04
相关资源
最近更新 更多