как преобразовать Mongo BasicDBList в неизменяемый список scala

#scala #mongodb #casbah

#scala #mongodb #касба

Вопрос:

У меня есть базовый список, который был сохранен в базе данных. Сейчас я считываю данные и пытаюсь преобразовать список в неизменяемый список scala, как показано:

 val collection = mongoFactory.getCollection("tokens")    
val appId = MongoDBObject("appId" -> id)
val appDBObject = collection.findOne(appId) 
val scope: List[String] = appDBObject.get("scope").asInstanceOf[List[String]]
  

Однако я получаю исключение приведения класса, в котором говорится, что невозможно преобразовать базовый список в неизменяемый список Scala.

Я пробовал различные комбинации, такие как преобразование в карту и т.д. Кажется, ничего не работает.

Ответ №1:

Поскольку MongoDB хранит массивы так же, как это делает JavaScript — в виде объекта с целочисленными ключами, указывающими их индекс, — BasicDBList необходим внутренне для представления объекта, выходящего из сети. Таким образом, в настоящее время Casbah не представляет его автоматически как список Scala…. BasicDBList — это хэш-карта, а не список.

ОДНАКО внутренне Casbah предоставляет неявные преобразования, позволяющие обрабатывать BasicDBList как LinearSeq[AnyRef]; LinearSeq немного отличается в дереве типов от List, но является более подходящим типом по ряду причин. К сожалению, вы не можете привести к неявным преобразованиям.

На данный момент я рекомендую вам получить элемент в виде DBList, а затем либо ввести аннотацию к нему как LinearSeq, который будет использовать неявный, либо просто вызвать для него ToList (неявный предоставит метод ToList).

 scala> val l = MongoDBList("foo", "bar", "baz")
l: com.mongodb.BasicDBList = [ "foo" , "bar" , "baz"]

scala> val obj = MongoDBObject("list" -> l)
obj: com.mongodb.casbah.commons.Imports.DBObject = { "list" : [ "foo" , "bar" , "baz"]}

scala> obj.as[BasicDBList]("list")
res8: com.mongodb.casbah.Imports.BasicDBList = [ "foo" , "bar" , "baz"]

scala> obj.as[BasicDBList]("list").toList
res9: List[AnyRef] = List(foo, bar, baz)
  

Методы as[T]: T и getAs[T]: Option[T] , кстати, предпочтительнее приведения, поскольку в них есть некоторые хитрости для массирования типов. Следующий выпуск Casbah будет включать код, так что, если вы запросите Seq, List и т.д., А это DBList, as и getAs автоматически преобразует их в запрошенный вами тип.

Комментарии:

1. Спасибо за этот ответ. Я тоже пробовал этот подход. Но я не смог выяснить, как преобразовать List[AnyRef] в List[String], поскольку я хочу результат в виде списка строк. Может быть просто, но не уверен, как это сделать.

2. @venividivamos list collect { case s: String => s } извлечет все String из a List[AnyRef] и вернет List[String] с ними.

3. Да, ответ @DCSobrals — лучший выбор. Поскольку вы не можете «вводить» коллекции в MongoDB, нет способа гарантировать, что содержимое относится к определенному типу, за исключением обхода коллекции. Собирать их было бы безопаснее. Фактически, я собираюсь использовать этот подход для следующего выпуска, чтобы «попытаться» привести всю коллекцию к заданному типу.

4. @Daniel Именно то, что я хотел. Большое спасибо.

5. Это все еще актуально с версии 2.1.5.0? Я получаю ошибку компиляции о том, что «значение ToList не является членом com.mongodb.BasicDBList»