如何在响应mongo和播放中使用'$ in'查询'_id'

时间:2013-10-29 12:11:45

标签: mongodb scala playframework playframework-2.2 reactivemongo

我的项目设置为playframework 2.2.0play2-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

5 个答案:

答案 0 :(得分:3)

注意:在ReactiveMongo邮件列表上复制我的回复。

首先,对不起我的回答延迟,我可能错过了你的问题。 Play-ReactiveMongo无法自己猜测Json数组的值是ObjectIds。这就是为什么你必须为每个看起来像这样的id创建一个Json对象:{"$oid": "526fda0f9205b10c00c82e34"}。当ReactiveMongo Play插件看到第一个字段为$oid的对象时,它会将其视为ObjectId,以便驱动程序可以为此值发送正确的类型(在这种情况下为BSONObjectID。)

实际上这是一个更普遍的问题:JSON格式与BSON格式完全不匹配。数字类型(BSONIntegerBSONLongBSONDouble),BSONRegexBSONDateTimeBSONObjectID就属于这种情况。您可以在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]]()))