我有一个有3个收藏品的股票价格警报应用程序
1)提醒
{
"_id" : ObjectId("5a9543c235434a185038e778"), //alert id
"1" : ObjectId("5a9543c035434a185038e743"), //user id
"2" : "xyz", //asset id
"3" : "EUR", //fiat set by the user
"4" : NumberDecimal("1000"), //price at which user wants alert
"5" : true, // true if 1000 was greater than price at the time of setting the alert
"6" : 0, //type 0 indicating it is a price alert
"__v" : 0
}
2)美元资产价值每2分钟更新一次,目前 2000 资产
{
"_id" : "xyz", //asset id
"1" : 997, //current price of the asset
}
3)每小时更新美元的菲亚特转换,目前 160 货币
{
"_id" : "EUR",
"1" : 0.811798
}
一个人必须能够设置一个警告“如果欧元中的xyz低于1000或高于1000,则提醒我”
对于测试数据,我设置了100000个警报,第一步是从我为其加入的资产表中找到资产xyz的当前价格
Alert
.aggregate([
{
$lookup: {
from: "assets",
localField: "2", //field containing asset id
foreignField: "_id", //foreign field with asset id
as: "s"
}
}
])
.allowDiskUse(true)
.exec((error, result) => {
if (error) {
console.log(error)
}
else {
console.log("Got", result.length, "documents mongoose")
}
mongoose.connection.close()
})
目前仅需11秒!
我希望能够将每种资产的当前价格乘以指定的货币,然后检查它是否高于或低于用户设定的水平,以便触发警报
例如,如果警报是xyz:EUR,我希望以美元获得XYZ的资产价格,将美元的价格变为欧元并乘以两者以获得最终价格xyz:EUR并检查该值是否更大小于或小于1000来触发警报
外部字段是一个_id字段,我假设它是默认索引的。我在localField 2上设置了一个索引:这是我的资产ID和3:这是我的法定符号
以下是我的目标
上 getIndexes()查询的结果[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.alerts"
},
{
"v" : 2,
"key" : {
"2" : 1
},
"name" : "2_1",
"ns" : "test.alerts",
"background" : true
},
{
"v" : 2,
"key" : {
"3" : 1
},
"name" : "3_1",
"ns" : "test.alerts",
"background" : true
}
]
我还运行了一个 explain()来检查发生了什么,尽管设置了索引,但它表明了一个COLLSCAN
{
"stages": [
{
"$cursor": {
"query": {},
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.alerts",
"indexFilterSet": false,
"parsedQuery": {},
"winningPlan": {
"stage": "COLLSCAN",
"direction": "forward"
},
"rejectedPlans": []
}
}
},
{
"$lookup": {
"from": "assets",
"as": "s",
"localField": "2",
"foreignField": "_id"
}
}
],
"ok": 1
}
任何建议,建议都会非常有帮助。谢谢
替代
我真的不想做的另一个选择是计算代码中的所有价格,并在警报集合中添加另一个字段,称为价格,每隔2分钟更新一次xyz:EUR和其他警报。潜在的1500资产x 160菲律宾将意味着每2分钟就有很多条目可以突破
更新1个Profiler输出
密钥未被使用!任何想法
getmore test.e1_sources 89ms Tue Feb 27 2018 19:22:28
command:{
"getMore" : NumberLong("6524439989055389783"),
"collection" : "alerts",
"batchSize" : 1000,
"$readPreference" : {
"mode" : "secondaryPreferred"
},
"$db" : "test"
} originatingCommand:{
"aggregate" : "alerts",
"pipeline" : [
{
"$lookup" : {
"from" : "assets",
"localField" : "2",
"foreignField" : "_id",
"as" : "s"
}
}
],
"allowDiskUse" : true,
"cursor" : {
"batchSize" : 1000
},
"$db" : "test"
} cursorid:NumberLong("6524439989055389783") keysExamined:0 docsExamined:0 cursorExhausted numYield:2 locks:{
"Global" : {
"acquireCount" : {
"r" : NumberLong(6000)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(3000)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(2999)
}
}
} nreturned:1000 responseLength:164393 protocol:op_query planSummary:COLLSCAN client:127.0.0.1 allUsers:[ ] user:
答案 0 :(得分:1)
一个人必须能够设置一个警告“如果欧元中的xyz低于1000或高于1000,则提醒我”
根据您提到的上述行。添加一个匹配阶段来过滤该用户ID的assetid。这将减少你必须加入的数据量。
Alert.aggregate([
{
$match:{
"1"://user id,
"2"://asset id
}
},
{
$lookup: {
from: "assets",
localField: "2", //field containing asset id
foreignField: "_id", //foreign field with asset id
as: "s"
}
}
])
.allowDiskUse(true)
.exec((error, result) => {
if (error) {
console.log(error)
}
else {
console.log("Got", result.length, "documents mongoose")
}
mongoose.connection.close()
})