Reactivemongo — вставка BSONObjectID и BSONDateTime

Я использую play2.5 + play2-reactivemongo 0.12.3.

BSONObjectID вставляется как массив, а BSONDateTime вставляется как NumberLong в mongoDB со следующими кодами.

> db.Example.find()
{ "_id" : { "array" : [ 89, 55, -10, 60, -40, 0, 0, -61, 0, -94, 126, 23 ] }, "created" : NumberLong("1496839744818") }

Я хочу, чтобы BSONObjectID был вставлен как ObjectID, а DateTime — как BSONDateTime. Можно ли сделать с параметром типа?

TemporalModel.scala

trait TemporalModel {
  var _id: Option[BSONObjectID]
  var created: Option[DateTime]
}

Пример.scala

import org.joda.time.DateTime
...

case class Example(
  var_id: Option[BSONObjectID],
  str: String,
  var created: Option[DateTime]
) extends TemporalModel

object Example {

  //implicit val objectIdRead: Reads[BSONObjectID] =
  val objectIdRead: Reads[BSONObjectID] =
    (__ \ "$oid").read[String].map { oid =>
      BSONObjectID(oid)
  }

  //implicit val objectIdWrite: Writes[BSONObjectID] = new Writes[BSONObjectID] {
  val objectIdWrite: Writes[BSONObjectID] = new Writes[BSONObjectID] {
    def writes(objectId: BSONObjectID): JsValue = Json.obj(
      "$oid" -> objectId.stringify
    )
  }

  //implicit val dateTimeRead: Reads[DateTime] =
  val dateTimeRead: Reads[DateTime] =
    (__ \ "$date").read[Long].map { dateTime =>
      new DateTime(dateTime)
  }

  //implicit val dateTimeWrite: Writes[DateTime] = new Writes[DateTime] {
  val dateTimeWrite: Writes[DateTime] = new Writes[DateTime] {
    def writes(dateTime: DateTime): JsValue = Json.obj(
      "$date" -> dateTime.getMillis
    )
  }

  implicit val objectIdFormats = Format(objectIdRead, objectIdWrite)
  implicit val dateTimeFormats = Format(dateTimeRead, dateTimeWrite)
  //implicit val bsonObjectIDJsonFormat = Json.format[BSONObjectID]
  implicit val exampleJsonFormat = Json.format[Example]

  def apply(str: String): Example = {
    new Example(null, str, null)
  }
}

BaseDAO.scala

class BaseDAO[T] {
  ...
  val collectionName: String
  lazy val collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection(collectionName))

  def toJs[K : Writes](o: K) = Json.toJson(o).as[JsObject]

  def insert(document: T)(implicit writer: Writes[T]): Future[T] = {
    document._id = Some(BSONObjectID.generate)
    document.created = Some(DateTime.now)
    collection.flatMap(_.insert(toJs(document)))
  }
}

ПримерDAO.scala

trait ExampleDAO extends BaseDAO[Example]

class ExampleDAOImpl @Inject() (val reactiveMongoApi: ReactiveMongoApi) 
extends ExampleDAO {
  val collectionName = "example"
}

person Uske    schedule 07.06.2017    source источник
comment
Ничего общего с вашим вопросом, но вы можете заменить Writes на OWrites для toJs параметра K, чтобы убедиться, что as[JsObject] не вызовет исключение.   -  person Cyrille Corpet    schedule 07.06.2017
comment
Не могли бы вы пояснить, что вас не устраивает в написанном вами коде?   -  person Cyrille Corpet    schedule 07.06.2017
comment
Спасибо за ваш совет. Я хочу, чтобы _id в примере класса case был вставлен как ObjectID, но он вставлен как массив, а также хочу, чтобы созданный был вставлен как ISODate. он вставлен как NumberLong с моим кодом.   -  person Uske    schedule 07.06.2017
comment
Действительно ли objectId.stringify преобразует BSONObjectID в хеш-строку? Не проверено, но я думаю, что BSONObjectID как двоичные данные преобразуются в массив из моего анализа. Почему бы тебе не использовать toString   -  person Orar    schedule 07.06.2017
comment
Я также пробовал toString. Но результат был таким же, как и stringify.   -  person Uske    schedule 07.06.2017


Ответы (1)


Проблема в том, что у вас слишком много имплицитов в области видимости. Однако, поскольку они разрешаются в макросе, ошибки компиляции, похоже, нет.

Что ты должен делать:

  • удалите все модификаторы implicit перед вашими Reads и Writes для BSONObjectID и DateTime
  • удалить bsonObjectIDJsonFormat (который имеет тот же тип, что и objectIdFormats, поэтому компилятор не должен разрешать это)
person Cyrille Corpet    schedule 07.06.2017
comment
Я закомментировал все неявное. Но ничего не меняется. - person Uske; 07.06.2017
comment
Не удаляйте все, только слово implicit перед вашими 4 Reads и Writes (оставьте Formats) и bsonObjectIDJsonFormat - person Cyrille Corpet; 07.06.2017
comment
Спасибо. Я неправильно понял. И это не решается модифицированным кодом. Я что-то упускаю? - person Uske; 07.06.2017
comment
Я изменил некоторые коды и пытался решить проблему. Но все еще не работает, как я ожидаю. - person Uske; 08.06.2017
comment
это странно, у меня тот же код, что и у вас в Example.scala, и он сериализует Example, как вы хотите. Вы пытались явно передать Writes[Example] вашему методу insert, чтобы увидеть, действительно ли он использует exampleJsonFormat? - person Cyrille Corpet; 08.06.2017
comment
Я добавил println() в objectIdWrite и подтвердил, что он не выводится через тестовый код. очень странно. - person Uske; 08.06.2017
comment
Вы должны проверить, скажем, с IntelliJ, что неявно используется, когда вы вызываете вставку. - person Cyrille Corpet; 08.06.2017
comment
Извините. Я только что подтвердил, что println вызывается один раз с тестом specs2. IntelliJ? моя среда разработки находится на ubuntu и vim.. - person Uske; 08.06.2017
comment
Он правильно вставлен, как я и ожидал!! Проблема заключалась в том, что я подтверждал через встроенный флапдудл mongodb со спецификациями2. Я не знаю, почему тестовый код позволяет вставлять данные в настоящий mongodb. В любом случае, большое спасибо. Я понял это после того, как установил IntelliJ на Mac. Это очень полезно. - person Uske; 09.06.2017