我应该如何在play2应用程序中构建嵌套的reactivemongo调用?

时间:2013-05-22 11:12:46

标签: mongodb scala asynchronous playframework playframework-2.1

我正在尝试在play2应用程序中将一些嵌套调用与reactivemongo结合起来。 我得到了从createObjects返回的对象列表。然后我循环遍历它们,检查集合中是否存在对象,如果没有,则插入它们:

def dostuff() = Action {
    implicit request =>
      form.bindFromRequest.fold(
        errors => BadRequest(views.html.invite(errors)),
        form => {
        val objectsReadyForSave = createObjects(form.companyId, form.companyName, sms_pattern.findAllIn(form.phoneNumbers).toSet)
          Async {
            for(object <- objectsReadyForSave) {
                collection.find(BSONDocument("cId" -> object.get.cId,"userId" ->
                object.userId.get)).cursor.headOption.map { maybeFound =>
                maybeFound.map { found =>
                  Logger.info("Found record, do not insert")
                } getOrElse {
                  collection.insert(object)
                }
              }
            }
            Future(Ok(views.html.invite(form)))
          }            
          })
   }

我觉得这种方式并不尽如人意,感觉不是“play2”和“reactivemongo”。 所以我的问题是:我应该如何构建嵌套调用以获得我想要的结果 并获取已插入的对象的信息?

2 个答案:

答案 0 :(得分:2)

这是我改写它的方式。

def dostuff() = Action { implicit request =>
  form.bindFromRequest.fold(
    errors => BadRequest(views.html.invite(errors)),
    form   => {
      createObjects(form.companyId,
        form.companyName,
        sms_pattern.findAllIn(form.phoneNumbers).toSet).map(ƒ)

      Ok(views.html.invite(form))
    }
  )
}

// ...
// In the model
// ...

def ƒ(cId: Option[String], userId: Option[String], logger: Logger) = {
  // You need to handle the case where obj.cId or obj.userId are None
  collection.find(BSONDocument("cId" -> obj.cId.get, "userId" -> obj.userId.get))
    .cursor
    .headOption
    .map { maybeFound =>
      maybeFound map { _ =>
        logger.info("Record found, do not insert")
      } getOrElse {
        collection.insert(obj)
      }
    }
}

可能存在一些语法错误,但这个想法就在那里。

答案 1 :(得分:2)

我不是ReactiveMongo中的mongoDB专家,但您似乎正在尝试使用NoSQL数据库,就像使用标准SQL数据库一样。请注意,mongoDB是异步的,这意味着操作可能会在将来执行,这就是插入/更新操作不会返回受影响的文档的原因。关于你的问题:

  

1如果对象不存在则插入它们并获取已插入的对象的信息?

您应该查看mongoDB db.collection.update()方法,并将upsert参数调用为true。如果您负担得起,如果文档已存在于数据库中,则会更新文档,否则将插入文档。同样,此操作不会返回受影响的文档,但您可以通过访问last error来检查受影响的文档数量。请参阅reactivemongo.api.collections.GenericCollection#update,其中会返回Future[LastError]

  

2对于插入的所有对象,将它们添加到列表中,然后使用Ok()调用返回它。

再次,不会返回插入/更新的文档。如果您确实需要返回完整的受影响文档,则需要进行另一个查询以检索匹配的文档。

我可能会以这种方式重写你的代码(没有错误/失败处理):

def dostuff() = Action {
    implicit request =>
        form.bindFromRequest.fold(
            errors => BadRequest(views.html.invite(errors)),
            form => {
                val objectsReadyForSave = createObjects(form.companyId, form.companyName, sms_pattern.findAllIn(form.phoneNumbers).toSet)
                Async {
                    val operations = for {
                        data <- objectsReadyForSave
                    } yield collection.update(BSONDocument("cId" -> data.cId.get, "userId" -> data.userId.get), data, upsert = true)

                    Future.sequence(operations).map {
                        lastErrors =>
                            Ok("Documents probably inserted/updated!")
                    }
                }
            }
        )
}

另见Scala期货:http://docs.scala-lang.org/overviews/core/futures.html

这真的很有用! ;)