首页 > 解决方案 > MongoDb 更新旧文档

问题描述

我是 MongoDb 和存储信息的 NoSQL 概念的新手。与 SQL Server 不同,在表中添加或更新列名将影响所有记录。我可以假设当我提取记录时,该列将在那里。它可能有也可能没有值,具体取决于它的设置方式。

但是,您将如何处理 MongoDb 中的情况,即您有一个过时的文档并且您想要提取它,而现在您的代码正在寻找一个不存在或刚刚重命名的属性?

标签: mongodbnosql

解决方案


不同技术的例子很少。

假设我们有一个pets包含以下文档的集合:

{
    kind: "cat",
    age: 2
}

在某个时候,我们添加了一个字段“nick”,所以新文档看起来像:

{
    kind: "cat",
    age: 2,
    nick: "Tom"
}

您的应用需要“昵称”字段来列出宠物。

  1. 使用默认值

    使用默认值更新旧文档(您可能将其称为 SQL 术语中的“ALTER TABLE”魔术):

    db.pets.updateMany({nick: {$exists: false}}, {$set: {nick: "NONAME"}});
    

    如果您需要支持这两个版本,则需要在运行时进行。

    在应用方面:

    db.pets.find({}).forEach(pet => print(p.nick || "NONAME") );
    

    在数据库方面:

    db.pets.aggregate([
        {$project: {
            kind: 1,
            age: 1,
            nick: { $ifNull: [ "$nick", "NONAME" ] }
        }}
    ])
    
  2. 忽略无效文件

    删除它们:

    db.pets.remove({nick: {$exists: false}})
    

    如果您需要同时支持这两个版本,则需要在运行时将它们过滤掉:

    db.pets.find({
        kind: {$exists: true},
        age: {$exists: true},
        nick: {$exists: true}
    );
    

    您可以通过指定type使其更具防御性:

    db.pets.find({
        kind: {$type: "string"},
        age: {$type: "int"},
        nick: {$type: "string"}
    );
    
  3. 停止程序执行

    db.pets.find({}).forEach(pet => if(!pet.nick){throw new Error("Pet " + pet._id + " has no nick!")} );
    

推荐阅读