Как запустить команду Distinct с помощью ReactiveMongo

Учитывая следующую коллекцию orders (первые два заказа имеют одинаковые issuer)...

{ "_id" : ObjectId("55d9ab6391fc103256107f15"), "issuer": ObjectId("55d0f641a100000401b7e454"), "description": "one" }
{ "_id" : ObjectId("55d9ab6391fc103256107f16"), "issuer": ObjectId("55d0f641a100000401b7e454"), "description": "two" }
{ "_id" : ObjectId("55d9ab6391fc103256107f17"), "issuer": ObjectId("55d0f641a100000401b7e477"), "description": "three" }

... Мне нужно получить List[String], содержащий идентификаторы заказов, связанных с issuer 55d0f641a100000401b7e454, поэтому я определил команду Distinct следующим образом:

package object commands {

  import reactivemongo.bson.{BSONString, BSONDocument}
  import reactivemongo.core.commands.{CommandError, BSONCommandResultMaker, Command}

  case class Distinct(
    collectionName: String,
    field: String,
    query: Option[BSONDocument] = None
  ) extends Command[List[String]] {

    override def makeDocuments = BSONDocument(
      "distinct" -> BSONString(collectionName),
      "key" -> field,
      "query" -> query
    )

    val ResultMaker = Distinct
  }

  object Distinct extends BSONCommandResultMaker[List[String]] {

    def apply(document: BSONDocument) = CommandError.checkOk(
      document,
      Some("distinct")
    ).toLeft(document.getAs[List[String]]("values").getOrElse(List.empty))
  }
}

Наконец, я вызываю его следующим образом:

def distinct(collectionName: String, field: String, selector: BSONDocument): Future[List[String]] = {
   ReactiveMongoPlugin.db.command(Distinct(
     collectionName, field, Some(selector)
   )).recover {
     case e: LastError => throw DaoErrors.DatabaseError(collectionName, e)
   }
 }

...

val query = BSONDocument("issuer" -> BSONObjectID("55d0f641a100000401b7e454")) 
distinct("orders", "_id", query).map { orderIds =>
  // orderIds should contain the order ids... but it is empty
}

Проблема в том, что CommandError.checkOk.toLeft в моем объекте Distinct всегда возвращает None.


person j3d    schedule 23.08.2015    source источник


Ответы (1)


  1. Вы можете использовать ReactiveMongo AggregationFramework, это должно выглядеть примерно так:

    import play.modules.reactivemongo.json.commands.JSONAggregationFramework._
    
    val query = Json.obj("issuer" -> Json.obj("$oid" -> "55d0f641a100000401b7e454"))
    
    collection.aggregate(Match(query), 
        List(Group(JsNull)("fieldName" -> AddToSet("someField")))
    )
    

    Он развивался в последних выпусках.

  2. Или, в вашем случае, почему бы просто не использовать find с проекцией.

    Если я понимаю, что _id — это id заказа, так зачем идти дальше, если достаточно простого поиска.

person mavarazy    schedule 23.08.2015
comment
К сожалению, я использую старую версию ReactiveMongo, и приведенные выше утверждения не компилируются. Во всяком случае, моя команда возвращает {"values":[{"$oid":"55d0f641a100000401b7e454"}],"stats":{"n":1,"nscanned":1,"nscannedObjects":1,"timems":0,"cursor":"BtreeCursor projectId_1"},"ok":1.0}... и это оператор document.getAs[List[String]]("values"), который на самом деле терпит неудачу, вероятно, потому, что он не находит подходящего автора. - person j3d; 23.08.2015
comment
А как насчет 2-го утверждения? Вы всегда можете обновить :) - person mavarazy; 23.08.2015
comment
Для старой версии вы можете посмотреть пример, упомянутый на github.com/ReactiveMongo/ReactiveMongo/ вопросы/155 - person cchantep; 24.08.2015