我正在尝试从mongo-db数据库中检索一些数据。我已经设置了一个用户帐户,我可以使用命令行工具检索一些数据:
C:\Program Files\MongoDB\Server\3.6\bin\mongo.exe" database.foocorp.com:27017/mydatabase -u salimfadhley -p secretpassowrd
MongoDB shell version v3.6.3
connecting to: mongodb://database.foocorp.com:27017/mydatabase
MongoDB server version: 3.4.4
WARNING: shell and server versions do not match
> db.mycollection.find()
... got loads of data back ...
我能够从Python查询相同的数据集,如下所示:
from pymongo import MongoClient
def main():
client = MongoClient(
'database.foocorp.com',
username='salimfadhley',
password='secretpassword',
authsource='dashboard',
authMechanism='SCRAM-SHA-1'
)
db = client.dashboard
collection = db["mycollection"]
print(collection.find_one())
if __name__ == "__main__":
main()
第一次按预期工作完美。
但是现在我想从Scala做同样的事情:
import org.mongodb.scala.{Document, MongoClient, MongoCollection}
object ConnectionDemo extends App {
val dbHost = "database.foocorp.com"
val dbPort = 27017
val dbUserName = "salimfadhley"
val dbPassword = "secretpassword"
val dbName = "mydatabase"
val collectionName = "mycollection"
val mongoClient = MongoClient(s"mongodb://$dbUserName:$dbPassword@$dbHost:$dbPort/?authsource=$dbName")
val mongoDatabase = mongoClient.getDatabase(dbName)
val result = mongoDatabase.getCollection(collectionName).find()
result.subscribe(
(d:Document) => println(d.toJson()),
(e:Throwable) => println(s"An error occurred, ${e.getMessage}"),
() => println("Done")
)
我的期望是这段代码应该为集合中的每件事打印出一个项目。当我使用Robo3T和mongo shell的完全相同的凭证查询集合时,我得到了大量的结果,所以我原本希望在这里看到相同的东西。
实际上这段代码似乎什么都不做:它从不打印任何结果,错误甚至“完成”。
此外,如果我故意提供错误的密码或主机名,它仍然绝对没有。如果连接参数完全错误,我希望看到某种错误消息。
我在这里做错了什么?
答案 0 :(得分:2)
正如您所指出的,问题是您不等待数据库的响应。我在你的回答中看到你使用Await - 虽然这是一个有效的事情,但如果你希望你的代码是异步的,你应该真的避免使用Await。当您的应用正在等待回复时,它无法做任何其他事情。
常见的解决方法是使用Scala Futures。未来的好处是,在其核心,你假设在某些时候会有响应,并且可以在Future等待完成时继续计算其他东西。如果要使用Future的值,可以在其中进行映射。这假定一旦未来完成,您将对结果做一些事情。使用Future的一般示例:
import scala.concurrent.Future
// assuming you have a method called callDatabase in another class called connector
val thingToWaitFor: Future[String] = ???
thingToWaitFor.map {
thing => // do something with this thing (thing is now of type String)
}
如果您需要等待多个期货,则需要在所有外部期货上使用Scala的flatMap功能,并且只在最内部的期货上进行映射:
import scala.concurrent.Future
val thingToWaitFor1: Future[String] = ???
val thingToWaitFor2: Future[String] = ???
val thingToWaitFor3: Future[String] = ???
thingToWaitFor1.flatMap {
thing1 =>
thingToWaitFor2.flatMap {
thing2 =>
thingToWaitFor3.map {
thing3 => // etc
}
}
}
当然,您可以在定义后的任何时候对这些映射值(thing1
,thing2
和thing3
)执行某些操作,而不仅仅是在最高位置或最低级别。
使用Futures比等待结果更受欢迎,特别是对于异步应用程序。如果您不是异步,那么我认为Await很好。只是觉得我给了另一种选择!
答案 1 :(得分:0)
愚蠢的我,答案是here。我所要做的就是等待结果传递,最简单的方法是使用Scala的“Await”功能。