【问题标题】:How do I specify multiple Join Conditions with $lookup in ReactiveMongo aggregation framework?如何在 ReactiveMongo 聚合框架中使用 $lookup 指定多个加入条件?
【发布时间】:2020-10-01 15:19:20
【问题描述】:

如何在 ReactiveMongo (0.17.1) 中使用 $lookup 指定多个加入条件,并牢记以下几点? - 根据the mongoDB documentation

用户集合

[
    {
      "name": "dogfrey",
      "field": "cowboy"
    },
    {
      "name": "catsville",
      "field": "spaceman"
    }
]

角色集合

[
    {
      "id": 0,
      "userType": "cowboy",
      "spaceman": "fiver",
      "num": 2
    },
    {
      "id": 1,
      "userType": "joker",
      "spaceman": "tenner",
      "num": 3
    },
    {
      "id": 2,
      "userType": "cowboy",
      "spaceman": "tenner",
      "num": 1
    }
]

MongoDb 查询

db.users.aggregate([
  {
    "$match": {
      "name": "dogfrey"
    }
  },
  {
    "$lookup": {
      "from": "roles",
      let: {
        "users_field": "$field"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$userType",
                "$$users_field"
              ]
            },
            
          }
        },
        {
          $project: {
            _id: 0
          }
        }
      ],
      "as": "dogs"
    }
  }
])

See here for the MongoPlayground example

ReactiveMongo documentation 不包含任何表明它可能不可能的示例。任何帮助表示赞赏!


也只是添加一些我尝试过的东西(不成功):

  def getResults(aColl: JSONCollection, bColl: JSONCollection)
                (id: BSONObjectID)(implicit request: Request[AnyContent]) = aColl.aggregateWith[JsObject]() {
    framework => import framework.{Match, Lookup, AddFields, Project, Sort, Ascending, Descending, Filter, Limit, Group, Sum, Push, Slice}

    ...

    val lookupJso = Lookup(
      from = bColl.name,
      let = Json.obj("fromDate" -> "$varData_e.plan_e.when_e.fromDate", "toDate" -> "$varData_e.plan_e.when_e.toDate"),
      pipeline = Json.arr(
        "$match" -> Json.obj("$expr" ->
            Json.obj("$and" -> Json.arr(
              Json.obj("$gte" -> Json.arr("$varData_e.dateTime", f"$$fromDate")),
              Json.obj("$lt" -> Json.arr("$varData_e.dateTime", f"$$toDate"))
            )),
         ),
        "$project" -> Json.obj("_id" -> 0)
      ),
      "temp_e.lookupTest1_e"
    )

    ...

  }.collect[List](Int.MaxValue, Cursor.FailOnError[List[JsObject]]())

我可以看到Lookup case class 看起来像这样:

  case class Lookup(
    from: String,
    localField: String,
    foreignField: String,
    as: String) extends PipelineOperator {
    import builder.{ document, elementProducer => element, string }
    val makePipe: pack.Document = document(Seq(
      element(f"$$lookup", document(Seq(
        element("from", string(from)),
        element("localField", string(localField)),
        element("foreignField", string(foreignField)),
        element("as", string(as)))))))
  }

【问题讨论】:

  • 你自己已经尝试过什么?哪个版本?
  • @cchantep 感谢您的回复。 ReactiveMongo 版本是 0.17.1,我在问题中添加了更多细节。感谢

标签: mongodb scala aggregation-framework reactivemongo


【解决方案1】:

版本 0.17.1 已超过一年(最新版本为 major 1.0)。

您可以在documentation 中看到,可以为 API 中未提供方便工厂的阶段定义原始聚合运算符。

import scala.concurrent.ExecutionContext

import reactivemongo.bson._
import reactivemongo.api.collections.bson.BSONCollection

def customAgg(coll: BSONCollection)(implicit ec: ExecutionContext) =
  coll.aggregateWith[BSONDocument]() { framework =>
    import framework.{ Match, PipelineOperator, Project }

    val lookup = PipelineOperator(BSONDocument(f"$$lookup" -> BSONDocument(
      "from" -> "roles",
      "let" -> BSONDocument("users_field" -> f"$$field"),
      "pipeline" -> Seq(
        Match(BSONDocument(f"$$expr" ->
          BSONDocument(f"$$eq" -> Seq(f"$$userType", f"$$$$users_field")))).
          makePipe,
        Project(BSONDocument("_id" -> 0)).makePipe),
      "as" -> "dogs")))

    Match(BSONDocument("name" -> "dogfrey")) -> List(lookup)
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2019-06-20
    • 2016-06-19
    • 1970-01-01
    相关资源
    最近更新 更多