使用 Meteor 方法从 MongoDB 下载大量文档
Posted
技术标签:
【中文标题】使用 Meteor 方法从 MongoDB 下载大量文档【英文标题】:Download large sets of documents from MongoDB using Meteor methods 【发布时间】:2021-12-09 12:35:18 【问题描述】:我正在尝试使用 Meteor 方法从集合(大约 12 MB)中导出所有文档,但它几乎总是使应用程序崩溃或从不返回结果。
我正在考虑将文档上传到 S3,然后向客户端发送下载链接,但是似乎有不必要的网络连接,并且会使过程更长。
有没有更好的方法从服务器到客户端获取大量数据?
这是该代码的示例,非常简单。
'downloadUserActions': () =>
if (Roles.userIsInRole(Meteor.userId(), ['admin']))
const userData = userActions.find().fetch();
return userData
谢谢。
【问题讨论】:
您是否有一个最小的可重现示例来解决问题?我不确定您的方法从根本上是否存在缺陷。可能是您的应用程序导致问题的原因。如果失败了,那么您总是可以公开一个旧的服务器路由(想想 REST API)来下载数据。 我同意@ChristianFritz。从理论上讲,通过 DDP 方法下载没有什么问题,因此它可能与您的代码有关,如果您无法使其与 DDP 一起使用,您可以随时求助于 REST。 @ChristianFritz 感谢您的输入,我也在想同样的事情,但是服务器保持沉默并且从不返回结果,我还会检查服务器是否存在内存问题但从未找到。我还将尝试使用文件系统库来流式传输数据,我会不断更新这个问题。 12MB 不够大,可能会导致您的应用崩溃。你还有autopublish
包吗?
【参考方案1】:
您可以使用一种方法,将请求拆分为多个:
获取文档计数 直到文档计数被完全提取 获取已获取文档的当前计数 获取下一组文档并跳过已经获取的文档为此,您需要在 mongo 查询中使用 skip
选项以跳过已获取的文档。
代码示例
const limit = 250
Meteor.methods(
// get the max amount of docs
getCount ()
return userActions.find().count()
,
// get the next block of docs
// from: skip to: skip + limit
// example: skip = 1000, limit = 500 is
// from: 1000 to: 1500
downloadUserActions (skip)
this.unblock()
return userActions.find(, skip, limit ).fetch()
)
客户:
// wrap the Meteor.call into a promise
const asyncCall = (name, args) => new Promise((resolve, reject) =>
Meteor.call(name, args, (err, res) =>
if (err)
return reject(err)
return resolve(res)
)
)
const asyncTimeout = ms => new Promise(resolve => setTimeout(() => resolve(), ms)
const fetchAllDocs = async (destination) =>
const maxDocs = await asyncCall('getCount')
let loadedDocs = 0
while (loadedDocs < maxDocs)
const docs = await asyncCall('downloadUserActions', loadedDocs)
docs.forEach(doc =>
// think about using upsert to fix multiple docs issues
destination.insert(doc)
)
// increase counter (skip value)
loadedDocs = destination.find().count()
// wait 10ms for next request, increase if server needs
// more time
await asyncTimeout(10)
return destination
将它与客户端上的本地 Mongo 集合一起使用:
await fetchAllDocs(new Mongo.Collection(null))
在函数之后,所有文档现在都存储在这个本地集合中。
使用limit
和超时(毫秒)值来找到用户体验和服务器性能之间的最佳平衡点。
其他改进
代码不会验证或验证请求。这取决于你!
Aölso 您可能会考虑添加故障安全机制,以防while
循环由于某些意外错误而永远无法完成。
进一步阅读
https://docs.meteor.com/api/methods.html#DDPCommon-MethodInvocation-unblock https://docs.meteor.com/api/collections.html#Mongo-Collection https://docs.meteor.com/api/collections.html#Mongo-Collection-find【讨论】:
以上是关于使用 Meteor 方法从 MongoDB 下载大量文档的主要内容,如果未能解决你的问题,请参考以下文章
在 Meteor 运行时,如何从另一个客户端访问 Meteor 的 MongoDB?