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

时间:2019-09-22 13:28:30

标签: mongodb mongodb-atlas

仅在价格或库存发生变化时,我才需要在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>
}

2 个答案:

答案 0 :(得分:0)

背景

数据模型:

收藏库存:

{
   _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:创建一个change stream来监视product_items.price的更新以更新product.price_lastupdate的值。 Here is the example

    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_last更新:可以为stock_lastupdate创建类似的变化流。
  • 多次插入或更新,因为我需要太多的性能:与在大型数组中插入/更新产品项不同,此数据模型提供了插入的灵活性,因为它将导致在product_items集合中插入单个文档。 / li>
  • 代码和stock_id是唯一的:通过在code and stock_id上创建唯一索引在查询的第一部分要格外小心

答案 1 :(得分:0)

我与MongoAtlas合作。我解决了使用 trigger 来更新 priceLastUpdate (operation_type:update,event_ordering:true,full_document:false)。

触发功能:

 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()     
        }
      }
    );
  }
};

但是我的multiinsert或multipleupdate问题仍然没有解决。当我使用 findOneAndModify 在350个循环中插入/更新350个项目时,执行时间约为18s。这是不可接受的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不知道此功能。

有什么主意吗?