gpt4 book ai didi

mongodb - 如何在 ReactiveMongo 模型中表示 GeoJSON 点?

转载 作者:可可西里 更新时间:2023-11-01 09:12:27 26 4
gpt4 key购买 nike

为了在 MongoDB 中进行地理空间查询,带有位置的文档(带有 2d2dsphere 地理空间索引)应该如下所示:

{
_id: …,
loc: {
type: "Point",
coordinates: [ <longitude>, <latitude> ]
}
}

我是 Scala、ReactiveMongo 和 Play Framework 的新手,但在我看来,使用此类位置的明显方法是通过案例类,例如:

case class Point(lon: Double, lat: Double)

网站 API 处理的 JSON 表示应该类似于:

{
_id: …
loc: [ <longitude>, <latitude> ]
}

现在,我不知道如何告诉我的 ReactiveMongo 模型在这些格式之间进行序列化/反序列化。

我的 Controller 看起来像这样:

package controllers

import play.api._
import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.Future

// Reactive Mongo imports
import reactivemongo.api._
import scala.concurrent.ExecutionContext.Implicits.global

// Reactive Mongo plugin
import play.modules.reactivemongo.MongoController
import play.modules.reactivemongo.json.collection.JSONCollection

object Application extends Controller with MongoController {
def collection: JSONCollection = db.collection[JSONCollection]("test")

import play.api.data.Form
import models._
import models.JsonFormats._

def createCC = Action.async {
val user = User("John", "Smith", Point(-0.0015, 51.0015))
val futureResult = collection.insert(user)
futureResult.map(_ => Ok("Done!"))
}
}

我尝试使用 PointWriter 和 PointReader。这是我的 models.scala:

package models

import reactivemongo.bson._
import play.modules.reactivemongo.json.BSONFormats._

case class User(
// _id: Option[BSONObjectID],
firstName: String,
lastName: String,
loc: Point)

case class Point(lon: Double, lat: Double)

object Point {
implicit object PointWriter extends BSONDocumentWriter[Point] {
def write(point: Point): BSONDocument = BSONDocument(
"type" -> "Point",
"coordinates" -> Seq(point.lat, point.lon)
)
}

implicit object PointReader extends BSONReader[BSONDocument, Point] {
def read(doc: BSONDocument): Point = Point(88, 88)
}
}

object JsonFormats {
import play.api.libs.json.Json
import play.api.data._
import play.api.data.Forms._

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val pointFormat = Json.format[Point]
}

当我调用 Controller 操作 createCC 时,我希望新创建的文档有一个格式正确的 Point 对象,但我实际得到的是这样的:

{
"_id": ObjectId("52ac76dd1454bbf6d96ad1f1"),
"loc": {
"lon": -0.0015,
"lat": 51.0015
}
}

所以我尝试使用 PointWriterPointReader 来告诉 ReactiveMongo 如何将这样的 Point 对象写入数据库完全没有效果.

任何人都可以帮助我理解我必须做什么吗?

(我有 PHP 背景,并尝试着手研究 Scala...)

更新:感谢 tmbo 的回答,我想出了这个作家:

val pointWrites = Writes[Point]( p =>
Json.obj(
"type" -> JsString("Point"),
"coordinates" -> Json.arr(JsNumber(p.lon), JsNumber(p.lat))
)
)

最佳答案

您面临的问题与 JSONCollectionBSONCollection 之间的混淆有关。

BSONCollectionreactivemongo 使用的默认集合。此实现需要一个 BSONDocumentWriter 和一个 BSONReader 的实现,以便案例类得到(反)序列化。

JSONCollection另一方面是 play-reactive 模块 使用的默认集合实现。由于您在 db.collection[JSONCollection]("test") 中将集合定义为 JSONCollection,因此您需要提供隐式 json 格式。

你提供的json格式是

implicit val pointFormat = Json.format[Point]

这会将对象序列化为以下格式

{
"lon": -0.0015,
"lat": 51.0015
}

如果你想将你的 Point 序列化为一个数组,你需要替换上面的隐式 pointFormat:

import play.api.libs.json._
import play.api.libs.json.Reads._

case class Point(lng: Double, lat: Double)

object Point {

val pointWrites = Writes[Point]( p => Json.toJson(List(p.lng, p.lat)))

val pointReads = minLength[List[Double]](2).map(l => Point(l(0), l(1)))

implicit val pointFormat = Format(pointReads, pointWrites)
}

你实际上不需要 BSONReaderBSONDocumentWriter

编辑:这是一个读取,它还验证了文档的 type 属性:

val pointReads =
(__ \ 'type).read[String](constraints.verifying[String](_ == "Point")) andKeep
(__ \ 'coordinates).read[Point](minLength[List[Double]](2).map(l => Point(l(0), l(1))))

关于mongodb - 如何在 ReactiveMongo 模型中表示 GeoJSON 点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20585295/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com