我的项目设置为playframework 2.2.0
和play2-reactivemongo 0.10.0-SNAPSHOT
。我想通过他们的id查询一些文档,方式类似于:
def usersCollection = db.collection[JSONCollection]("users")
val ids: List[String] = /* fetched from somewhere else */
val query = ??
val users = usersCollection.find(query).cursor[User].collect[List]()
作为查询我试过:
Json.obj("_id" -> Json.obj("$in" -> ids)) // 1
Json.obj("_id.$oid" -> Json.obj("$in" -> ids)) // 2
Json.obj("_id" -> Json.obj("$oid" -> Json.obj("$in" -> ids))) // 3
第一个和第二个返回空列表,第三个失败,错误为assertion 10068 invalid operator: $oid
。
答案 0 :(得分:3)
注意:在ReactiveMongo邮件列表上复制我的回复。
首先,对不起我的回答延迟,我可能错过了你的问题。
Play-ReactiveMongo无法自己猜测Json数组的值是ObjectIds。这就是为什么你必须为每个看起来像这样的id创建一个Json对象:{"$oid": "526fda0f9205b10c00c82e34"}
。当ReactiveMongo Play插件看到第一个字段为$oid
的对象时,它会将其视为ObjectId,以便驱动程序可以为此值发送正确的类型(在这种情况下为BSONObjectID
。)
实际上这是一个更普遍的问题:JSON格式与BSON格式完全不匹配。数字类型(BSONInteger
,BSONLong
,BSONDouble
),BSONRegex
,BSONDateTime
和BSONObjectID
就属于这种情况。您可以在MongoDB文档中找到更多详细信息:http://docs.mongodb.org/manual/reference/mongodb-extended-json/。
答案 1 :(得分:0)
我设法解决了这个问题:
val objectIds = ids.map(id => Json.obj("$oid" -> id))
val query = Json.obj("_id" -> Json.obj("$in" -> objectIds))
usersCollection.find(query).cursor[User].collect[List]()
因为play-reactivemongo格式仅在“$ oid”后跟字符串时才考虑BSONObjectID
implicit object BSONObjectIDFormat extends PartialFormat[BSONObjectID] {
def partialReads: PartialFunction[JsValue, JsResult[BSONObjectID]] = {
case JsObject(("$oid", JsString(v)) +: Nil) => JsSuccess(BSONObjectID(v))
}
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case oid: BSONObjectID => Json.obj("$oid" -> oid.stringify)
}
}
不过,我希望有一个更清洁的解决方案。如果没有,我想这是一个很好的拉动请求。
答案 2 :(得分:0)
我想知道将id转换为BSONObjectID是否以这种方式更安全:
val ids: List[String] = ???
val bsonObjectIds = ids.map(BSONObjectID.parse(_)).collect{case Success(t) => t}
这只会生成有效的BSONObjectID(并丢弃无效的BSONObjectID) 如果你这样做:
val objectIds = ids.map(id => Json.obj("$oid" -> id))
你的objectIds可能不是有效的,这取决于字符串id是否真的是BSONObjectID的stringify版本
答案 3 :(得分:0)
如果您导入play.modules.reactivemongo.json._
,则无需使用任何$ oid格式化程序。
import play.modules.reactivemongo.json._
...
val ids: Seq[BSONObjectID] = ???
val selector = Json.obj("_id" -> Json.obj("$in" -> ids))
usersCollection.find(selector).cursor[User].collect[Seq]()
答案 4 :(得分:0)
我尝试了以下方法,并且对我有用:
val listOfItems = BSONArray(51, 61)
val query = BSONDocument("_id" -> BSONDocument("$in" -> listOfItems))
val ruleListFuture = bsonFutureColl.flatMap(_.find(query, Option.empty[BSONDocument]).cursor[ResponseAccDataBean]().
collect[List](-1, Cursor.FailOnError[List[ResponseAccDataBean]]()))