Как в scala извлечь данные из результата запроса к mongodb?
Создал из scala подключение к БД на mongodb. Подключилось успешно, код такой:
val config = ConfigFactory.load().getConfig("akka")
implicit val system = ActorSystem("asl", config)
val uri = "mongodb://mnguser:123@localhost:27017"
val mongoClientSettings = MongoClientSettings.builder().applyConnectionString(ConnectionString(uri))
.serverApi(ServerApi.builder().version(ServerApiVersion.V1).build())
.build()
val client = MongoClient(mongoClientSettings)
val database = client.getDatabase("magazine")
val collection: MongoCollection[Document] = database.getCollection("article")
// val result = collection.find().first // Здесь бы выбрать результат в читаемом виде
Внутри монги лежат документы вот в таком виде:
{
_id":{"$oid":"623190cb6a1c5c237f93a63c"}
"article": "Основы биологии",
"version": "1.1.0.0",
"download": "some_link_here"
}
Мне нужно выбрать все статьи, причем каждая статья должна быть последней версии, т.е. если есть три документа "Основы биологии" с версиями "1.1.0.0.", "1.12.0.0", "2.0.0.1", то должен выбраться документ с версией "2.0.0.1" как самый новый, аналогично с другими статьями. И отдать результат в json.
Если целиком такая задача слишком сложна, помогите хотя бы фрагментом кода по извлечению данных. Например, в массив\список объектов с полями article, version, download.
Ответы (1 шт):
Задачу в итоге решил. Получилось не совсем в scala-стиле, зато работает. Если кто-то сможет поправить, чтобы было красивее, welcome.
- Создаем класс для хранения информации о статьях:
case class ArticleInfo(article: String, version: String, download: String) {
override def toString(): String = "[article='" + article+ "', version='" + version + "', download='" + download+ "']"
}
- Вот этим фрагментом можно извлечь данные из коллекции. Сначала выбираем все документы, превращаем их в объекты. Потом непосредственно извлекаем с помощью Await.result, получаем Seq со строками:
val sel = collection.find(Document())
.map(dbo => ArticleInfo(
dbo.getString("article"),
dbo.getString("version"),
dbo.getString("download")))
Await.result[Seq[ArticleInfo]](sel.toFuture(), Duration.Inf)
- Вот такой класс понадобится, чтобы дать методу сортировки алгоритм сравнения версий наших статей:
object VersionOrdering extends Ordering[ArticleInfo] {
override def compare(x: ArticleInfo, y: ArticleInfo): Int = {
var xNums: Array[Int] = x.version.split("\\.").map(_.toInt);
var yNums: Array[Int] = y.version.split("\\.").map(_.toInt);
for (i <- 0 to xNums.size) {
if (xNums(i) < yNums(i))
return -1
if (yNums(i) < xNums(i))
return 1
}
return 0
}
}
Ну и наконец вот демо получения сортированных статей. Только вместо тестового набора данных подставляем данные из базы, полученные в пункте 2.
object SortTest {
def test: Unit = {
// Сгруппируем статьи по названию, чтобы одинаковые попали в единый Seq
val articles: Map[String, Seq[ArticleInfo]] = getAllArticles.groupBy(_.name)
// В этот массив будем складывать по одному экземпляру каждой статьи (свежий)
val arr = new Array[ArticleInfo](articles.size)
var i = 0
for (article <- articles) {
// _2 - это keys словаря, у нас там набор статей одного вида, но разных версий
arr(i) = getLatest(article._2)
i+=1
}
arr.foreach(println(_))
}
private def getLatest(history: Seq[ArticleInfo]): ArticleInfo = {
var arr = history.toArray
// Сортировка по возрастанию, значит самая свежая будет в конце
arr.sorted(VersionOrdering).last
}
private def getAllArticles: Seq[ArticleInfo] = {
Seq(
ArticleInfo("Основы биологии", "2.19.1.3", "link_here"),
ArticleInfo("Птицы нашего края", "12.0.4.5", "link_here"),
ArticleInfo("Ядовитые грибы", "3.22", "link_here"),
ArticleInfo("Основы биологии", "12.0.9.7", "link_here")
)
}
}