如何在特殊条件下在MongoDb中多次插入文档



我需要在MongoDB中多次插入/更新price_lastupdate,并且仅在价格或股票更改时stock_lastupdate。

重要思考:

  • 可以插入新产品(代码+stock_id是唯一的(
  • 仅在价格更改时更新price_lastupdate
  • 仅在股票更改时更新stock_lastupdate然后之前
  • 多次插入或更新,因为我需要太多的性能
  • 代码stock_id是唯一的

输入数据:

productList = [
{
"code": "123",
"stock_id": "CZ01",
"price": 11.2,
"stock": 10
},
{
"code": "124",
"stock_id": "CZ02",
"price": 12.9,
"stock": 9
},
{
"code": "135",
"stock_id": "CZ01",
"price": 9.9,
"stock": 11
},
{
"code": "110",
"stock_id": "CZ02",
"price": 1.7,
"stock": 5
},
];

目标结构(代码 + stock_id是唯一的(:

{
"code": "<string>",
"stock_id": "<string>",
"price": <double>,
"price_lastupdate": <date>,
"stock": <int>,
"stock_lastupdate":<date>
}

背景:

  • MongoDB在3.6版中添加了富有表现力的更新,以使用$[]和$[itentifier]运算符更新数组中的项目,如果您计划使用现有数据模型,则可以利用这些运算符
  • 但是,您的案例的数据模型采用第三种类型,该类型基于MongoDB提出的一到N模型的模式设计模式。特别是:使用父引用的一对一

数据模型:

收藏库存:

{
_id: "CZ01"
stock_provider: "ABC",
supplier_id:"SUP1"
}

收集product_items:

{
"code": "<string>",
"stock_id": "CZ01",
"price": <double>,
"price_lastupdate": <date>,
"stock": <int>,
"stock_lastupdate":<date>
}

查询

  • 可以插入新产品(代码 + stock_id是唯一的(:在code and stock_id上创建复合唯一索引以保持product_items集合中的唯一性
  • 仅当价格比以前更改时更新price_lastupdate:创建更改流以监视 product_items.price 上的更新,以更新product.price_lastupdate的值。下面是示例:

    const mongo = require("mongodb").MongoClient; mongo.connect("mongodb://localhost:27017/?replicaSet=rs0").then(client => { console.log("Connected to MongoDB server"); // Select DB and Collection const db = client.db("mydb"); const collection = db.collection("product_items"); pipeline = [ { $match: { "fullDocument.price": { $gte: 250 } } } ]; // Define change stream const changeStream = collection.watch(pipeline); // start listen to changes changeStream.on("change", function(event) { collection.update({_id:fullDocument}, {$set:{fullDocument.price_lastupdate:fullDocument.price}}) }); });

  • 仅在股票比以前更改时更新stock_lastupdate:可以为stock_lastupdate创建类似的更改流。
  • 多次插入或更新,
  • 因为我需要太多的性能:此数据模型不是在大型数组中插入/更新产品项,而是提供了插入的灵活性,因为它将导致在集合中插入单个文档product_items
  • 代码和stock_id是唯一的:通过在查询的第一部分创建唯一的索引来照顾code and stock_id

我使用MongoAtlas。我解决了使用触发器更新价格上次更新的问题(operation_type:更新,event_ordering:真,full_document:假(。

触发功能:

exports = function(changeEvent){
if(changeEvent.updateDescription.updatedFields.price !== undefined){
context.services.get("xxx").db("xxx").collection("product_items")
.findOneAndUpdate({
_id: changeEvent.documentKey._id
},
{
$set:{
price_lastupdate: new Date()     
}
}
);
}
};

但是我对多个插入或多个更新的问题仍未解决。当我使用findOneAndModify在 350 个周期上插入/更新 350 个项目时,执行时间约为 18 秒。这是不可接受的 10000+ 项。

我目前的HTTP服务:

exports = function(payload, response) {
const {data} = payload.query;
const productPrices = JSON.parse(data);
let products = context.services.get("xxx").db("xxx").collection("product_items");
productPrices.forEach(oneProductPrice => {
context.functions.execute("setProductPrice", oneProductPrice);
});
return  "OK";
};

我当前的函数setProductPrice(从HTTP服务调用(:

exports = function(product){
let products = context.services.get("xxx").db("xxx").collection("product_items");
products.findOneAndUpdate({
code: product.code,
stock_id: product.stock_id
},
{
$set:{
price: product.price,
},
$setOnInsert:{
code: product.code,
stock_id:product.stock_id,
price_lastupdate: new Date()
}
},
{
upsert: true,
});
};

我搜索了批量插入/更新

var bulk = db.items.initializeUnorderedBulkOp();
....

但Mongo Atlas不知道这个功能。

知道吗?

最新更新