在NodeJs应用程序中,我有一个代码片段:
- check if an element exist (1 query)
- if present, update some value of it (1 query)
- else, add a new record (1 query) and delete an older one (1 query)
所以基本上是4个query for "single"的任务。下面是我的完整代码:
let candleData;
try {
candleData = await Candle.findOne({ instrument_name: instrumentName, exchangeType: exchangeType, dt: dt });
if (!candleData) {
try {
// add new candle
let newCandle = {
instrument_name: instrumentName,
exchangeType: exchangeType,
dt: dt,
o: o,
h: h,
l: l,
c: c
}
await Candle.create(newCandle);
// remove older candle
await Candle.deleteMany({ instrument_name: instrumentName, exchangeType: exchangeType, dt: { $lt: dtOlder } });
} catch (error) {
console.log(error);
return;
}
} else {
// update candle
candleData.c = c;
await candleData.save();
}
} catch (error) {
console.log(error);
return;
}
我可以将其转换为批量操作吗?改善整个链条?
注意:我正在寻找/移除不同的项目。"where"是不同的。对dt=dt求出,对dt小于dtOlder求出。所以这是不一样的。所以它不是upsert指令。
这里有一些文档要做一些测试:
{ "_id": { "$oid": "62c40373d08fcf4ca03eb4b4" }, "instrument_name": "BTCBUSD", "exchangeType": "BINANCE", "dt": 1657005300000, "o": "20264.80000000", "h": "20290.73000000", "l": "20178.66000000", "c": "20211.63000000"}
{ "_id": { "$oid": "62c40373d08fcf4ca03eb4b5" }, "instrument_name": "BTCBUSD", "exchangeType": "BINANCE", "dt": 1657006200000, "o": "20213.33000000", "h": "20218.26000000", "l": "20155.26000000", "c": "20202.61000000"}
{ "_id": { "$oid": "62c40373d08fcf4ca03eb4b6" }, "instrument_name": "BTCBUSD", "exchangeType": "BINANCE", "dt": 1657007100000, "o": "20202.61000000", "h": "20238.23000000", "l": "20172.76000000", "c": "20192.74000000"}
{ "_id": { "$oid": "62c40373d08fcf4ca03eb4b7" }, "instrument_name": "BTCBUSD", "exchangeType": "BINANCE", "dt": 1657008000000, "o": "20192.75000000", "h": "20192.75000000", "l": "20033.95000000", "c": "20090.00000000"}
{ "_id": { "$oid": "62c40373d08fcf4ca03eb4b8" }, "instrument_name": "BTCBUSD", "exchangeType": "BINANCE", "dt": 1657008900000, "o": "20090.00000000", "h": "20098.49000000", "l": "19930.00000000", "c": "19989.98000000"}
试试这个:
db.candleData.updateOne(
{ instrument_name: instrumentName, exchangeType: exchangeType, dt: dt },
{
$set: { c: c },
$setOnInsert: {
instrument_name: instrumentName,
exchangeType: exchangeType,
dt: dt,
o: o,
h: h,
l: l
}
},
{ upsert: true }
)
确保过滤器只匹配单个文档。
如果您的情况不适合使用upsert
,MongoDB Realm Function
或Database Trigger
,
我认为您的逻辑是合理的。
如果需要删除的文档数量为1或0,则可以在一个查询中完成。比如:
$match
的共同点。如果这里没有匹配的情况是合理的,则应将此插入$facet
的两个分支中。- 用
$facet
区分found
/notFound
两种情况。如果找到,替换需要的字段,如果没有,将更新(需要删除)的文档限制为1。 - 格式,并使用"deleted"将
notFound
案例更新为新文档。文档_id。 - 使用
$ifNull
设置一个新的文档更新,根据我们的情况:found
/notFound
。 - 使用
$merge
更新文档(所有情况以一个更新文档结束)。
db.collection.aggregate([
{$match: {instrument_name: instrument_name, exchangeType: exchangeType}},
{
$facet: {
found: [{$match: {dt: dt}}, {$set: {c: c}}],
notFound: [{$match: {dt: {$lt: dtOlder }}}, {$limit: 1}]
}
},
{
$set: {
found: {$first: "$found"},
notFound: {$mergeObjects: [
{$first: "$notFound"},
{dt: dt, o: o, h: h, l: l, c: c, instrument_name: instrumentName,
exchangeType: exchangeType}]}
}
},
{$project: {newObj: {$ifNull: ["$found", "$notFound"]}}},
{$merge: {into: "collection"}}
])
看看它在操场的例子中是如何工作的