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
集合的引用_id
s的新字段兴趣,有执行查询的顺序,
-
当
interest
(新字段)字段不存在时,查找配置文件查询和项目仅需要字段_id
和interests
,并使用forEach
迭代循环
trim interests
遍历映射的字符串循环
从创建的interests
集合中通过其name
字段查找interests
引用_id
更新查询以添加在配置文件集合中具有 _id
s 的 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
警告:
在生产服务器中执行之前,在本地/开发服务器中测试此步骤。 在执行查询之前备份您的数据库集合。 预测字段和架构名称可以替换为原始名称。
【讨论】:
你好,我只是好奇。是否可以将新兴趣字段中的数据复制到旧兴趣字段而不是删除旧兴趣字段?这是为了保留该领域的逻辑标签,因为它代表多种利益而不仅仅是一种利益。 目前情况如何?您在每个文档中都有interest
和intereses
两个字段吗?您是打算删除旧的兴趣字段数据还是已将其删除?
我有兴趣和兴趣,我正在使用新创建的兴趣字段。但是,为了逻辑上的连贯性,我想回到兴趣上。换句话说,将感兴趣的数据复制到旧的兴趣字段中。 2/ 我对每一份文件都感兴趣。但是,不是兴趣,因为它不再使用。 3/ 正如我所说,旧的兴趣字段数据现在没用了,因为我对它感兴趣。
您可以使用将字段查询从interest
重命名为interests
,参见playground,这会将interests
替换为interest
。并且您还必须将代码中的字段名称从 interest
更改为 interests
。
非常感谢:D以上是关于MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
将数组中对象的字段添加到同一数组中对象的另一个字段MongoDB
MongoDB如何将数组中的字段类型从字符串更改为数组并保持原始值
如何根据另一个字段更新 mongodb 中的数组 dict 元素