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?

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

  interests: {
    type: [String],
  },

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

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

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

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

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

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

第 1 步:

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

第 2 步:

应用程序中后台使用interests的地方,使用interest填充即可


第三步:(只执行查询)

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

  • $project显示兴趣字段只是因为我们要解构它
  • $unwind解构interests数组
  • $group by interests and select unique field, and trim white space from interests string
  • $project 显示 name 字段,如果你想添加你想要的字段
  • $out 将创建一个新集合 interests 并将所有 interests 写入新生成的 _id 字段
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/新集合中的 output/result 将类似于:

[
    {
      "_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"
    }
  ]


第四步:(只执行查询)

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

  1. interest新字段)字段不存在时,仅查找配置文件查询和项目必填字段_idinterests并迭代使用 forEach
  2. 循环
  3. trim interests 字符串遍历映射
  4. 通过创建的 interests 集合
  5. name 字段找到 interests 引用 _id
  6. 更新查询以添加 interest 个在配置文件集合中具有 _id 的字段
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")
      ]
    }
  ]


第 5 步:

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

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

Playground


Warning:

  • Test this steps in your local/development server before executing in production server.
  • Take backup of your database collections before executing queries.
  • Field and schema names are predicted you can replace with your original name.