MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是啥?

Posted

技术标签:

【中文标题】MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是啥?【英文标题】:MongoDb: What's the best approach to modify a model field from an array of strings to an array of ids that would refer to another model?MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是什么? 【发布时间】:2021-06-27 04:03:21 【问题描述】:

我有一个 Profile 模型,其中包含此字段:

  interests: 
    type: [String],
  ,

我的应用程序已经运行了一段时间。所以这意味着对于几个文档,这个字段已经被一个字符串数组填充了。

为了实现某些目标,我需要创建一个模型Interest,其中包含一个字段name,然后在Profile 中引用它,如下所示:

  interests: [
    type: Schema.Types.ObjectId,
    ref: "interests",
  ],

字段name 应包含Profile.interests 中已存在的string 兴趣。 这是我认为我会遵循的方法:

    创建Interest 模型。 用现有的Profile.interests 字符串填充name 字段。 一种。执行此操作时,将 Profile.interests 替换为新创建的 Interest 文档的 _ids。 湾。确保 Interest.name 是唯一的。 C。删除空格。 应用中的interests在后端使用的地方,用populate填写。

感觉这不是一个安全的操作。所以我想听听你对此的看法。有更好的方法吗?我应该避免这样做吗? 谢谢。

【问题讨论】:

如果安全性和 0 停机时间高于复杂性,我会将应用程序/模式更新和数据库/数据更新解耦。如果您为新的兴趣数组使用单独的字段,并向应用程序添加转换逻辑以使用这两种格式,您可以在旅途中逐步更新数据库。 你的意思是我应该创建一个新的interest2 字段,它的类型应该是首先引用兴趣模型的id 数组? 是的,但前提是你必须这样做。如果您能够承受停机时间来关闭服务器、升级应用程序、更新数据库并运行测试以在维护窗口期间确认数据完整性和一致性,那么在代码方面实现会更简单。 我明白了。感谢您的提示! 【参考方案1】:

第 1 步:

    为兴趣创建模型,
根据兴趣架构指定所需字段并为特定字段设置属性 根据您的要求在选项中指定集合名称 创建一个模型并在模型中指定您想要的名称
const InterestsSchema = new mongoose.Schema(
     name:  type: String  ,
     collection: "interests" 
);
const Interests = mongoose.model("Interests", InterestsSchema);
    不要删除 interests 字段,而是添加新字段 interest您可以选择所需的字段),为了安全起见,只要您觉得当前更新正常工作,您可以删除它,更新配置文件架构,
根据您的要求更新interest字段,现在新增字段为interest
  interests: 
    type: [String]
  ,
  interest: [
    type: Schema.Types.ObjectId,
    ref: "interests"
  ],

第 2 步:

无论在后端使用应用中的interests,使用interest 并填充它们。


第三步:(只执行查询)

为兴趣创建一个集合并存储个人资料集合中的所有唯一兴趣字符串,因此编写一个聚合查询以选择唯一字符串并存储在兴趣集合中,您可以在指定后在 mongo shell 或您正在使用的任何编辑器中执行此查询您的原始个人资料集合名称,

$project 只显示兴趣字段,因为我们要解构它 $unwind 解构 interests 数组 $group 按兴趣选择唯一字段,并从 interests 字符串中修剪空白 $project 显示 name 字段,如果您想添加所需字段 $out 将创建一个新集合 interests 并使用新生成的 _id 字段写入所有 interests
db.getCollection('profile').aggregate([
   $project:  interests: 1  ,
   $unwind: "$interests" ,
   $group:  _id:  $trim:  input: "$interests"    ,
   $project:  _id: 0, name: "$_id"  ,
   $out: "interests" 
])

Playground

您有示例输入:

[
  
    "_id": 1,
    "interests": ["sports","sing","read"]
  ,
  
    "_id": 2,
    "interests": ["tracking","travel"]
  
]

执行上述查询后,interests/新集合中的输出/结果将类似于:

[
    
      "_id": ObjectId("5a934e000102030405000000"),
      "name": "travel"
    ,
    
      "_id": ObjectId("5a934e000102030405000001"),
      "name": "sports"
    ,
    
      "_id": ObjectId("5a934e000102030405000002"),
      "name": "read"
    ,
    
      "_id": ObjectId("5a934e000102030405000003"),
      "name": "tracking"
    ,
    
      "_id": ObjectId("5a934e000102030405000004"),
      "name": "sing"
    
  ]

第四步:(只执行查询)

在配置文件集合中添加来自interests集合的引用_ids的新字段兴趣,有执行查询的顺序,

    interest新字段)字段不存在时,查找配置文件查询和项目仅需要字段_idinterests,并使用forEach 迭代循环 trim interests 遍历映射的字符串循环 从创建的interests 集合中通过其name 字段查找interests 引用_id 更新查询以添加在配置文件集合中具有 _ids 的 interest 字段
db.getCollection('profile').find(
   interest:  $exists: false  , 
   _id: 1, interests: 1 ).forEach(function(profileDoc) 

    // TRIM INTEREST STRING
    var interests = profileDoc.interests.map(function(i)
        return i.trim();
    );

    // FIND INTERESTS IDs
    var interest = [];
    db.getCollection('interests').find(
       name:  $in: interests  , 
       _id: 1 ).forEach(function(interestDoc)
        interest.push(interestDoc._id);
    );

    // UPDATE IDS IN PROFILE DOC
    db.getCollection('profile').updateOne(
         _id: profileDoc._id ,
         $set:  interest: interest  
    );

);

您有示例输入:

[
  
    "_id": 1,
    "interests": ["sports","sing","read"]
  ,
  
    "_id": 2,
    "interests": ["tracking","travel"]
  
]

执行上述查询后,您的个人资料集合中的结果将类似于:

  [
    
      "_id": 1,
      "interests": ["sports","sing","read"],
      "interest": [
        ObjectId("5a934e000102030405000001"),
        ObjectId("5a934e000102030405000002"),
        ObjectId("5a934e000102030405000004")
      ]
    ,
    
      "_id": 2,
      "interests": ["tracking","travel"],
      "interest": [
        ObjectId("5a934e000102030405000000"),
        ObjectId("5a934e000102030405000003")
      ]
    
  ]

第五步:

现在您已经完成了所有步骤,并且您已经新添加了interest 字段 并且旧字段interests 字段仍处于安全模式,只要确保一切正常您可以删除旧的interests 字段,

从所有配置文件中删除旧字段 interests 字段
db.getCollection('profile').updateMany(
   interests:  $exists: true  , 
   $unset:  "interests": 1  
);

Playground


警告:

在生产服务器中执行之前,在本地/开发服务器中测试此步骤。 在执行查询之前备份您的数据库集合。 预测字段和架构名称可以替换为原始名称。

【讨论】:

你好,我只是好奇。是否可以将新兴趣字段中的数据复制到旧兴趣字段而不是删除旧兴趣字段?这是为了保留该领域的逻辑标签,因为它代表多种利益而不仅仅是一种利益。 目前情况如何?您在每个文档中都有interestintereses 两个字段吗?您是打算删除旧的兴趣字段数据还是已将其删除? 我有兴趣和兴趣,我正在使用新创建的兴趣字段。但是,为了逻辑上的连贯性,我想回到兴趣上。换句话说,将感兴趣的数据复制到旧的兴趣字段中。 2/ 我对每一份文件都感兴趣。但是,不是兴趣,因为它不再使用。 3/ 正如我所说,旧的兴趣字段数据现在没用了,因为我对它感兴趣。 您可以使用将字段查询从interest 重命名为interests,参见playground,这会将interests 替换为interest。并且您还必须将代码中的字段名称从 interest 更改为 interests 非常感谢:D

以上是关于MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将带有引用的关联数组作为值保存在教义-mongodb中

将数组中对象的字段添加到同一数组中对象的另一个字段MongoDB

MongoDB如何将数组中的字段类型从字符串更改为数组并保持原始值

如何根据另一个字段更新 mongodb 中的数组 dict 元素

如何使用 javascript var 引用 Mongodb 集合字段

python 操作mongoDB指令