【问题标题】:Mongoose findOneAndUpdate + upsert always replaces existing documentMongoose findOneAndUpdate + upsert 总是替换现有文档
【发布时间】:2021-07-10 21:35:17
【问题描述】:

我有一个我想用 findOneAndUpdate 更新的集合。除此之外,我还有两个字段(isHandled、isNotADuplicate)应该是:

  • 插入时默认为“假”
  • 更新时保持不变(例如,isHandled 保持“真”)

我发现

  • isHandled、isNotADuplicate 始终默认为“false”
  • _id 也会在每次更新时重新生成(我使用复合键来查询文档,而不是 _id)

我的模特

export const QuickbrainFindingSchema = new Schema<QuickBrainFindingDocument>({
    
    connectedApplicationType: { type: String, required: true, enum: ['jira'] },//e.g. jira
    clientKey: { type: String, required: true },//e.g. 135eb702-156c-3b67-b9d0-a0c97548xxxx
    
    //key
    projectKey: { type: String, required: true },//e.g. AL
    type: { type: String, required: true },
    doc1key: { type: String, required: true },//e.g. AL-7
    doc2key: { type: String, required: true },//e.g. AL-16
    
    //data
    calculationDate: { type: SchemaTypes.Date, default: Date.now },
    direction: { type: String, required: true },
    reasonAndMetric: { type: SchemaTypes.Mixed, reason: true },
    scoreSummary: { type: String, reason: true },

    isHandled: { type: SchemaTypes.Boolean, default: false },
    isNotADuplicate: { type: SchemaTypes.Boolean, default: false },

    similarityReference: { type: SchemaTypes.ObjectId, required: true, ref: "QuickbrainSimilarityMatrix" }

}, {
    //options
});

QuickbrainFindingSchema.index(
    { connectedApplicationType: 1, clientKey: 1, project: 1, doc1key: 1, doc2key: 1, type: 1 },
    { unique: true, name: "compoundKey" }
);

export const QuickbrainFindingModel = model<QuickBrainFindingDocument>("QuickbrainFinding", QuickbrainFindingSchema);

我的代码

public async addFinding(
        projectKey: string,
        doc1key: string,
        doc2key: string,
        type: ET_FindingType
        , data: QuickbrainFindingData): Promise<QuickbrainFinding> {

        let keyFull: QuickbrainFindingKey = {
            connectedApplicationType: this.connectedApplicationType,
            clientKey: this.clientKey,
            projectKey: projectKey,
            doc1key: doc1key,
            doc2key: doc2key,
            type: type
        };

        let insertObj: QuickbrainFinding = <QuickbrainFinding><unknown>{};
        Object.assign(insert, keyFull);
        Object.assign(insert, data);

        delete (<any>insertObj).isHandled;
        delete (<any>insertObj).isNotADuplicate;

        return new Promise<QuickbrainFinding>(function (ok, nok) {

                QuickbrainFindingModel.findOneAndUpdate(
                    keyFull, { $set: insertObj},
                    {
                        runValidators: true,
                        upsert: true,
                        setDefaultsOnInsert: true,
                        new: true,
                        omitUndefined: true,//I think only available for findAndReplace(..)
                    })
                .lean().exec(function (err, result) {
                    if (err) {
                        nok(err);
                    }
                    else
                        ok(result)
                });

        });

    }

Mongoose 调试输出

        quickbrainfindings.findOneAndUpdate(
            {
                connectedApplicationType: 'jira',
                clientKey: '135eb702-256c-3b67-b9d0-a0c975487af3',
                projectKey: 'ITSMTEST',
                doc1key: 'ITSMTEST-7',
                doc2key: 'ITSMTEST-10',
                type: 'Email'
            },
            {
                '$setOnInsert':
                    { __v: 0, isHandled: false, isNotADuplicate: false, _id: ObjectId("60789b02c094eb3ef07d2929") },
                '$set': {
                    connectedApplicationType: 'jira',
                    clientKey: '135eb702-256c-3b67-b9d0-a0c975487af3', projectKey: 'ITSMTEST', doc1key: 'ITSMTEST-7', doc2key: 'ITSMTEST-10', type: 'Email',
                    calculationDate: new Date("Thu, 15 Apr 2021 19:58:58 GMT"),
                    direction: '2', scoreSummary: '100.0%',
                    similarityReference: ObjectId("60789b029df2079dfa8aa15a"),
                    reasonAndMetric: [{ reason: 'Title Substring', metricScore: '100%' },
                    { reason: 'Title TokenSet', metricScore: '54%' }, { reason: 'Description TokenSet', metricScore: '100%' }]
                }
            },
            {
                runValidators: true, upsert: true, remove: false, projection: {},
                returnOriginal: false
            }
        )

会发生什么

找到了现有的文档,但是当它们被更新时,我很困惑:

  • _id 被重新生成
  • isHandledisNotADuplicate 被重置为“false”(尽管 insertObj 不包含它们)
  • 查看调试输出时,我可以看到新的 _id 是 $setOnInsert 的前一个,这让我很困惑,因为选择器有效

值得注意的

  • keyFull用于查询已有文档,不包含_id
  • delete (&lt;any&gt;insertObj).isHandled

【问题讨论】:

  • 如果 _id 改变了,这意味着文档被删除并重新插入
  • 感谢您的回复。但是为什么会发生这种情况,因为我正在执行 findOneAndUpdate()?
  • 我觉得这对我来说更像是 findOneAndReplace - docs.mongodb.com/manual/reference/method/…

标签: mongodb mongoose upsert


【解决方案1】:

承认这一点很尴尬,但感谢Joe我发现了问题。

在每个 findOneAndUpdate / Upsert 之前,我都有一个删除语句删除现有文档管道:

  • 删除旧文档
  • 计算新文档
  • Upsert 新文档 -> 总是导致 Insert
            let matchAnyDoc = this.filterForDocKeyAny(projectKey, docKeyAny, findingType);
            matchAnyDoc.forEach(async (condition) => {
                QuickbrainFindingModel.deleteMany(condition).exec(function (err, res) {
                    if (err) {
                        nok(err);
                    } else {
                        ok();
                    }
                });

            }, this);

【讨论】:

    猜你喜欢
    • 2016-04-30
    • 2014-09-26
    • 2015-11-23
    • 2016-04-25
    • 1970-01-01
    • 2017-08-13
    • 2019-10-05
    • 2019-07-02
    • 1970-01-01
    相关资源
    最近更新 更多