我有一个允许用户使用自己的自定义数据的应用程序,所以我不知道数据是什么。但是,我确实希望允许他们对数据进行排序。 这可能是大量数据,mongodb最终给了我内存错误(限制为32MB)
解决此问题的最佳方法是什么?如何允许用户按未知字段对大量数据进行排序?
答案 0 :(得分:1)
MongoDB允许您以可以在模式中存储对象和对象关系的方式设计模式,因此您可以允许用户存储任何类型的信息。正如@kevinadi所说,最大限制为32MB。就排序而言,它可以在您的服务器端完成。
这是我在MongoDB和Mongoose ORM中存储对象时尝试的示例
var mongoose = require("mongoose");
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
lowercase: true,
trim: true,
match: [/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, "Please fill a valid email address"]
},
custInfo:{
type:Object,
required: true
}
isConfirmed: {
type: Boolean,
required: true,
default: false
},
confirmedOn:{
type: Date,
required: true,
default: Date.now()
}
});
module.exports = mongoose.model("user",userSchema);
答案 1 :(得分:1)
由于您已经标记了这个问题,因为我假设流星,所以您具有默认的流星环境,可以在其中使用客户端轻量级Mongo collections。
这使您有机会发布(发布)/返回(方法)几乎未排序的数据,并让客户处理此任务。
这样想:只有100个客户要求发布有关每个排序操作更新的发布(因为订阅参数发生了变化,因此发布也发生了变化)。
这已经导致您的服务器消耗大量RAM,以使观察者(OPLOG等)运行100个出版物,每个出版物都查询大量文档。
可能的解决方案如下所述。请记住,它们不限于任何前端,而只是一个概念上的描述。根据您的前端环境,您将必须包括反应性等。
服务器
Meteor.publish('hugeData', function () {
return MyCollection.find({ ...})
})
客户端
const handle = Meteor.subscribe('hugeData')
if (handle.ready()) {
const sortedData = MyCollection.find({ ... }, {sort: { someField: -1 } })
}
这里是一个很大的优点,如果使用cursor.observeChanges
,则可以通知客户完整性状态。
请注意,如果您想向后扫描(返回最新版本的文档),可以使用hint
option on find:
Meteor.publish('hugeData', function () {
return MyCollection.find({ ...}, { hint: { $natural : -1 })
})
与{ sort: { fieldName: -1} }
相比,它的性能更高。
现在,解决方案A可能仍然存在问题,因为如果有很多订阅者,它仍然要消耗大量RAM。一种替代方法(尤其是在实时数据更改不太重要的情况下)是使用“流星方法”:
服务器
Meteor.method('hugeData', function () {
return MyCollection.find({ ...}).fetch()
})
请注意,这需要fetch
个文档,否则将引发unhandledPromiseRejection
。
客户端
这需要在客户端上使用LocalCollection
,即与服务器端集合不同步,否则您将在文档同步方面遇到问题:
const HugeData = new LocalCollection(null) // note the null as collection name!
const insertUpdate = document => {
if (LocalCollection.findOne(document._id)) {
delete document._id
return LocalCollection.update(document._id, document)
} else {
return LocalCollection.insert(document)
}
}
Meteor.call('hudeData', (err, data) => {
data.forEach(insertUpdate)
})
然后,您可以在客户端上使用LocalCollection
来投影接收到的数据。
总而言之,将负载转移到客户端是一个很好的权衡。只要您让他们知道什么时候需要投影就可以了。
答案 2 :(得分:0)
我当前的想法是另外一个索引集合,其中包含1.entity id,2个字段名和3.field值。 将该集合编入索引,然后从那里提取有序的实体ID,稍后再通过ID加载完整的相关文档。