如何在 ReactiveMongo 聚合框架中使用 $lookup 指定多个连接条件?
How do I specify multiple Join Conditions with $lookup in ReactiveMongo aggregation framework?
如何在 ReactiveMongo (0.17.1) 中使用 $lookup 指定多个连接条件并牢记以下几点? - 根据 the mongoDB documentation.
用户collection
[
{
"name": "dogfrey",
"field": "cowboy"
},
{
"name": "catsville",
"field": "spaceman"
}
]
角色collection
[
{
"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)))))))
}
Release 0.17.1 is more than one year old (latest version being the 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)
}
如何在 ReactiveMongo (0.17.1) 中使用 $lookup 指定多个连接条件并牢记以下几点? - 根据 the mongoDB documentation.
用户collection
[
{
"name": "dogfrey",
"field": "cowboy"
},
{
"name": "catsville",
"field": "spaceman"
}
]
角色collection
[
{
"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)))))))
}
Release 0.17.1 is more than one year old (latest version being the 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)
}