Mongoose:批量更新插入,但仅在满足某些条件时才更新记录

Posted

技术标签:

【中文标题】Mongoose:批量更新插入,但仅在满足某些条件时才更新记录【英文标题】:Mongoose: Bulk upsert but only update records if they meet certain criteria 【发布时间】:2018-06-26 11:39:51 【问题描述】:

我正在为我正在构建的网站设计一个物品库存系统。

用户的库存是从 Web API 加载的。然后处理此信息,使其更适合我的网络应用程序。我正在尝试将所有项目记录合并到一个 MongoDB 集合中 - 因此其他用户库存将缓存在同一个地方。我必须处理的是删除旧项目记录,如果它们从用户的库存中丢失(即他们将其出售给某人),并且还要更新新项目。请注意,我查看了几个有关批量更新插入的 Stack Overflow 问题,但我找不到任何有关条件更新的信息。

每个项目都有两个唯一标识符(classIdinstanceId),我可以通过它们查找它们(我必须使用两个 ID 来匹配它),它们保持不变。有关该项目的某些信息(例如其名称)可能会更改,因此我希望能够在获取新的库存信息时更新这些记录。我还希望将我的网站以前从未见过的新项目添加到我的数据库中。

一旦处理了从 Web API 返回的数据,它就会留在大量对象中。这意味着我可以使用批量写入,但是,我不知道如何使用具有多条记录的条件进行更新插入。

这是我的项目架构的一部分:

const ItemSchema = new mongoose.Schema(
    ownerId: 
        type: String,
        required: true
    ,
    classId: 
        type: String,
        required: true
    ,
    instanceId: 
        type: String,
        required: true
    ,
    name: 
        type: String,
        required: true
    
    // rest of item attributes...
);

用户库存通常包含 600 件或更多件,最大数量为 2500 个。

更新插入这么多数据的最有效方法是什么?谢谢

更新:

我在实施批量插入问题的解决方案时遇到了麻烦。我做了一些假设,我不知道它们是否正确。我将_ 解释为lodash,response.body 解释为API 返回的JSON,myListOfItems 也解释为相同的项目数组。

import Item from "../models/item.model";
import _ from 'lodash';

async function storeInventory(items) 
    let bulkUpdate = Item.collection.initializeUnorderedBulkOp();

    _.forEach(items, (data) => 
        if (data !== null) 
            let newItem = new Item(data);
            bulkUpdate.find(
                classId: newItem.classId,
                instanceId: newItem.instanceId
            ).upsert().updateOne(newItem);
            items.push(newItem);
        
    );

    await bulkUpdate.execute();

每当我运行此代码时,它都会抛出一个错误,抱怨 _id 字段被更改,当我创建的架构对象未指定与架构有关的任何内容时,并且少数嵌套架构对象没有当我将它们更改为对象时,结果会有所不同。

我知道如果没有_id 被发送到 MongoDB,它会自动生成一个,但如果它正在更新一条记录,它无论如何都不会这样做。我还尝试在每个项目上将 _id 设置为 null,但无济于事。

我对接受的答案有什么误解吗?还是我的代码中其他地方的问题?

【问题讨论】:

Bulk upsert in MongoDB using mongoose的可能重复 这能回答你的问题吗? Trying to do a bulk upsert with Mongoose. What's the cleanest way to do this? 【参考方案1】:

这就是我的做法:

        let bulkUpdate = MyModel.collection.initializeUnorderedBulkOp();

        //myItems is your array of items
        _.forEach(myItems, (item) => 
            if (item !== null) 
                let newItem = new MyModel(item);
                bulkUpdate.find( yyy: newItem.yyy ).upsert().updateOne(newItem);
            
        );

        await bulkUpdate.execute();

我认为代码可读性强且易于理解。您可以对其进行调整以使其适用于您的情况:)

【讨论】:

所以从我收集到的信息来看,要使用两个唯一 ID 进行搜索,我可以使用 bulkUpdate.find( classId: newItem.classId, instanceId: newItem.instanceId ).upsert().updateOne(newItem);?感谢您提供的内容丰富的示例。 我在实施此解决方案时遇到问题。当我尝试运行此代码时,我得到WriteError("code":16837,"index":0,"errmsg":"The _id field cannot be changed。我不知道这是否与嵌套模式有关,但有些东西试图更改 _id 字段,这在我执行更新时会导致错误。 您是否在“newItem”对象中设置了“_id”字段?如果没有,如果没有更多代码,我将无能为力。 我已经更新了我的答案,以包括我对您提供的答案的实施。我做了一些我认为不太正确的假设。感谢您的帮助。 好的,我认为错误来自items.push(newItem);。我想我通过添加变量 myListOfItems 来误导你,我只是用它来存储来自其他来源的项目。我正在更新我的答案以删除它。

以上是关于Mongoose:批量更新插入,但仅在满足某些条件时才更新记录的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose (mongodb) 批量插入、删除、更新和无操作

仅在满足条件时填充

仅在满足某些条件时才调用 Safari Content Blocker 扩展?

如何制作 Segue Pass 数据并且仅在满足某些条件时执行

GetRequestStream() 返回 WebException 超时...但仅在某些机器上

Instagram 公共 API (/?__a=1) 有效,但仅在某些时候有效