gpt4 book ai didi

javascript - Mongoose 找到一个并推送到文档数组

转载 作者:可可西里 更新时间:2023-11-01 09:44:00 26 4
gpt4 key购买 nike

我是 MongoDB 和 Mongoose 的新手,我正在尝试使用它来保存股票报价以供日间交易分析。所以我想象了这个架构:

symbolSchema = Schema({
name:String,
code:String
});

quoteSchema = Schema({
date:{type:Date, default: now},
open:Number,
high:Number,
low:Number,
close:Number,
volume:Number
});

intradayQuotesSchema = Schema({
id_symbol:{type:Schema.Types.ObjectId, ref:"symbol"},
day:Date,
quotes:[quotesSchema]
});

通过我的链接,我每分钟都会收到这样的信息:

日期 |符号 |打开|高 |低 |关闭 |体积

2015-03-09 13:23:00|AAPL|127,14|127,17|127,12|127,15|19734

我必须:

  1. 找到符号 (AAPL) 的 ObjectId。
  2. 发现该交易品种的intradayQuote文档是否已经存在(交易品种和日期组合)
  3. 发现报价数组中是否存在该交易品种的分钟OHLCV数据(因为它可以重复)
  4. 更新或创建文档并更新或创建数组中的引号

如果引号已经存在,我可以在不费力的情况下完成这个任务,但是这个方法可以在引号数组中创建重复的条目:

symbol.find({"code":mySymbol}, function(err, stock) {
intradayQuote.findOneAndUpdate({
{ id_symbol:stock[0]._id, day: myDay },
{ $push: { quotes: myQuotes } },
{ upsert: true },
myCallback
});
});

我已经试过了:

  • $addToSet 而不是 $push,但不幸的是,这似乎不适用于文档数组
  • { id_symbol:stock[0]._id, day: myDay, 'quotes["date"]': myDate findOneAndUpdate 的条件下;但不幸的是,如果 mongo 找不到它,它会立即创建一个新文档,而不是附加到引号数组。

有没有一种方法可以在不使用更多查询的情况下使它正常工作(我已经使用了 2 个)?我是否应该重新考虑我的架构以促进这项工作?任何帮助将不胜感激。谢谢!

最佳答案

基本上放一个$addToSet运算符(operator)无法为您工作,因为您的数据不是真实的 "set"根据定义,它是“完全不同”对象的集合。

这里的另一个逻辑意义是,您将在数据到达时对其进行处理,无论是作为单个对象还是提要。我假设它是某种形式的许多项目的提要,并且您可以使用某种流处理器来为每个收到的文档达到此结构:

{
"date": new Date("2015-03-09 13:23:00.000Z"),
"symbol": "AAPL",
"open": 127.14
"high": 127.17,
"low": 127.12
"close": 127.15,
"volume": 19734
}

转换为标准的十进制格式和 UTC 日期,因为一旦从数据存储中检索到数据,任何语言环境设置实际上都应该是您的应用程序的域。

我至少还会通过删除对其他集合的引用并将数据放在那里来稍微平整您的“intraDayQuoteSchema”。您仍然需要在插入时进行查找,但读取时额外填充的开销似乎比存储开销更昂贵:

intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});

这取决于您的使用模式,但这样可能更有效。

剩下的真正归结为什么是可以接受的

stream.on(function(data) {

var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;

symbol.findOne({ "code": symbol },function(err,stock) {

intraDayQuote.findOneAndUpdate(
{ "symbol.code": symbol , "day": myDay },
{ "$setOnInsert": {
"symbol.name": stock.name
"quotes": [data]
}},
{ "upsert": true }
function(err,doc) {
intraDayQuote.findOneAndUpdate(
{
"symbol.code": symbol,
"day": myDay,
"quotes.date": data.date
},
{ "$set": { "quotes.$": data } },
function(err,doc) {
intraDayQuote.findOneAndUpdate(
{
"symbol.code": symbol,
"day": myDay,
"quotes.date": { "$ne": data.date }
},
{ "$push": { "quotes": data } },
function(err,doc) {

}
);
}
);
}
);
});
});

如果您实际上不需要在响应中修改文档,那么您可以通过在此处实现批量操作 API 并在单个数据库请求中发送此包中的所有更新来获得一些好处:

stream.on("data",function(data) {

var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;

symbol.findOne({ "code": symbol },function(err,stock) {
var bulk = intraDayQuote.collection.initializeOrderedBulkOp();
bulk.find({ "symbol.code": symbol , "day": myDay })
.upsert().updateOne({
"$setOnInsert": {
"symbol.name": stock.name
"quotes": [data]
}
});

bulk.find({
"symbol.code": symbol,
"day": myDay,
"quotes.date": data.date
}).updateOne({
"$set": { "quotes.$": data }
});

bulk.find({
"symbol.code": symbol,
"day": myDay,
"quotes.date": { "$ne": data.date }
}).updateOne({
"$push": { "quotes": data }
});

bulk.execute(function(err,result) {
// maybe do something with the response
});
});
});

重点是只有一个语句会实际修改数据,并且由于这些都是在同一个请求中发送的,因此应用程序和服务器之间的来回更少。

另一种情况是,在这种情况下,在另一个集合中引用实际数据可能会更简单。然后这就变成了处理更新插入的简单问题:

intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[{ type: Schema.Types.ObjectId, ref: "quote" }]
});


// and in the steam processor

stream.on("data",function(data) {

var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;

symbol.findOne({ "code": symbol },function(err,stock) {
quote.update(
{ "date": data.date },
{ "$setOnInsert": data },
{ "upsert": true },
function(err,num,raw) {
if ( !raw.updatedExisting ) {
intraDayQuote.update(
{ "symbol.code": symbol , "day": myDay },
{
"$setOnInsert": {
"symbol.name": stock.name
},
"$addToSet": { "quotes": data }
},
{ "upsert": true },
function(err,num,raw) {

}
);
}
}
);
});
});

真正归结为将报价数据嵌套在“日”文档中对您有多重要。主要区别在于,如果您想根据某些“引用”字段的数据查询这些文档,或者以其他方式忍受使用 .populate() 从其他收藏。

当然,如果引用并且报价数据对您的查询过滤很重要,那么您始终可以查询该集合以获取匹配并使用 $in_id 值。查询“day”文档以仅匹配包含那些匹配的“quote”文档的日期。

根据您的应用程序使用数据的方式,选择哪条路径最为重要,这是一个重大决定。希望这会指导您了解实现您想要实现的目标背后的一般概念。

P.S 除非您“确定”您的源数据始终是四舍五入到精确“分钟”的日期,否则您可能希望使用与用于获取离散“日”相同的日期舍入数学。

关于javascript - Mongoose 找到一个并推送到文档数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28952581/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com