Создание класса case для встроенного массива MongoDB с помощью Salat и Scala
Я пытаюсь понять, как правильно сериализовать документ из MongoDB в моем проекте Scala. Проблема, с которой я столкнулся, заключается в том, что я не уверен, что делать, когда в моем документе есть поле "Массив", и как его обрабатывать в Scala. Вот как выглядит документ в MongoDB:
> db.injuries.findOne()
{
"_id" : ObjectId("5220ef71bbf8af333d000001"),
"team_id" : 86,
"league" : "NFC",
"team_name" : "Arizona Cardinals",
"players" : [
{
"player_id" : 9864,
"date" : "8/26/2013",
"position" : "TE",
"name" : "Rob Housler",
"injury" : "is doubtful for 9/8 against St. Louis",
"status" : "Doubtful",
"fantasy" : "",
"injured" : "True",
"type" : "ankle"
},
{
"player_id" : 11610,
"date" : "8/25/2013",
"position" : "G",
"name" : "Jonathan Cooper",
"injury" : "may be placed on injured reserve",
"status" : "Out",
"fantasy" : "",
"injured" : "True",
"type" : "leg"
},
{
"player_id" : 9126,
"date" : "4/3/2013",
"position" : "LB",
"name" : "Daryl Washington",
"injury" : "will be eligible to return on 10/6 against Carolina",
"status" : "Suspended",
"fantasy" : "",
"injured" : "True",
"type" : "four-game suspension"
}
],
"updated_at" : ISODate("2013-08-30T19:16:01.466Z"),
"created_at" : ISODate("2013-08-30T19:16:01.466Z")
}
>
Теперь мне нужно создать класс case, чтобы я мог создать собственный сериализатор для этого документа и доставить его клиенту. Я начал создавать класс case, как показано ниже:
case class Injury(_id: ObjectId = new ObjectId, team_id: Int, team_name: String, league: String, players: List[????], created_at: Option[Date] = None, updated_at: Option[Date] = None, id: Option[ObjectId] = None )
Я не обязательно хочу создавать класс кейса для игрока, потому что хеш-коды игрока выглядят по-разному в других коллекциях в зависимости от контекста. У меня может быть массив игроков, скажем, для коллекции "расписаний", и я не собираюсь перечислять там данные о травмах. Это не реальная ссылка на коллекцию игроков, это просто список с хэшами, где поле называется "игроки". В идеале я могу выяснить, как написать сериализацию, которая будет просто выводить это при запросе идентификатора этой команды:
{
"team_id": 86,
"team_name": "Arizona Cardinals",
"players": [
{
"player_id": 9864,
"date": "8/26/2013",
"position": "TE",
"name": "Rob Housler",
"injury": "is doubtful for 9/8 against St. Louis",
"status": "Doubtful",
"fantasy": "",
"injured": "True",
"type": "ankle"
},
{
"player_id": 11610,
"date": "8/25/2013",
"position": "G",
"name": "Jonathan Cooper",
"injury": "may be placed on injured reserve",
"status": "Out",
"fantasy": "",
"injured": "True",
"type": "leg"
},
{
"player_id": 9126,
"date": "4/3/2013",
"position": "LB",
"name": "Daryl Washington",
"injury": "will be eligible to return on 10/6 against Carolina",
"status": "Suspended",
"fantasy": "",
"injured": "True",
"type": "four-game suspension"
}
]
}
Что еще мне нужно сделать, чтобы иметь возможность получить этот окончательный документ JSON? Я знаю, что Salat может обработать сериализацию для класса case... но я не уверен, как обрабатывать атрибут игроков здесь. Вот начало сериализатора, над которым я начал работать, но до сих пор не знаю, как вписать карту игроков в этот список:
class InjurySerializer extends CustomSerializer[Injury](format => ({
case JObject(
("id", JString(id)) ::
("team_id", JString(team_id)) ::
("team_name" , JString(team_name)) ::
("league" , JString(league)) :: Nil) =>
Injury(new ObjectId, team_id.asInstanceOf[Int], team_name.asInstanceOf[String], league.asInstanceOf[String])
}, {
case injury: Injury =>
JObject.apply(
"team_id" -> JInt(injury.team_id),
"team_name" -> JString(injury.team_name),
"league" -> JString(injury.league)
)
}))
И тогда у меня есть простой помощник, чтобы получить все документы:
object Injury {
def findAll = {
val results = InjuryDAO.findAll
results.map(grater[Injury].asObject(_)).toList
}
}
Это прекрасно работает, но не включает карту игроков, как предложено выше.
2 ответа
Массивы не поддерживаются. Сделайте это списком, последовательностью, почти любым другим типом коллекции, и ваш документ будет правильно сериализован и десериализован.
https://github.com/novus/salat/wiki/Collections
Создайте класс кейса игрока со всеми возможными полями и используйте аргументы по умолчанию, чтобы охватить все кейсы.
Если есть слишком много разных случаев, чтобы покрыть, то это когда вещи становятся действительно безобразными. По сути, вы пытаетесь десериализовать данные, которые не имеют ожидаемой структуры, как... что именно? Я не добавил Map[String, Any]
поддержка господствующего Salat, хотя есть невыполненная просьба тянуть.
Вам, вероятно, придется использовать какой-то пользовательский сериализатор, я предполагаю, что у вас есть дескриптор родительского объекта - давайте назовем это повреждение
val playerRefs = injury.get("palyers")
var obj = MongoDBObject("list" -> playerRefs )
obj.as[MongoDBList]("list").toList.foreach {
value =>
val playerDef = value.asInstanceOf[BasicDBObject]
// Access values from player -
val name = playerDef.get("name")asInstanceOf[String]
// Build your case class
}