MongoDB (Mongoose) 数据结构问题

MongoDB (Mongoose) data structure question

我很好奇在 Mongo 中表现这种情况的最佳方式。我有自己的想法,但我很好奇一般的 consensus/best 实践究竟是什么。

假设我有两个 collections:-

Employees
 --> _id
 --> FirstName
 --> Surname
 --> Email

Comments
  --> _id
  --> PersonReference
  --> CommentDate
  --> Comment

现在想象一下,员工可以来来去去,'Employees' collection 总是 up-to-date。但是,如果员工发表过评论,则必须提供评论的完整信息,包括评论者。

我建议解决这个问题的方法是组织这样的结构:-

Employees
 --> _id: _id
 --> FirstName: string
 --> Surname: string
 --> Email: string

Comments
  --> _id: _id
  --> CommentDate: date
  --> Comment: string
  [-] --> PersonReference
  [+] --> Employee: object { _id: id, FirstName: string, Surname: string, Email:string }

所以基本上,我会有一个 'Active Employees' 的列表,并且在发表评论时,我会将员工信息复制到评论 collection 文档中(而不是使用参考).

从高层次的角度来看,这被认为是最佳做法吗?

非常感谢

许多数据库实现了 no-delete 类集合,为每个文档实现了一个 delete/active 标志。

例如,Employees 集合将变为:

Employees
 --> _id: _id
 --> FirstName: string
 --> Surname: string
 --> Email: string
 --> Active: boolean

通过这种方式,您可以跟踪已删除的员工数据,并在您有数据库大小限制的情况下防止文档重复。

PS:如今,如果用户要求删除,您可以解决保留用户数据的问题 (RGPD)


编辑:如果 Employees 文档已 更新 并且您想 保留员工的名字、姓名、邮件、等等,当时他制作了 Comment.

在评论集合中复制员工信息确实是个坏主意。 当需要更改员工信息时,也需要在评论中更新。

您有几个选择:

1-) 在 Employee 模式中嵌入评论:

在此方法中,我们没有单独的 Comments 集合。

如果你不需要独立查询评论,这个方法很有意义。 这样我们就可以在一个数据库访问中访问用户和 his/her 评论,而无需任何连接(填充或查找)。

这个模式可以是这样的:

const mongoose = require("mongoose");

const employeeSchema = new mongoose.Schema({
  firstName: String,
  username: String,
  email: String,
  comments: [
    new mongoose.Schema({
      commentDate: Date,
      comment: String
    })
  ]
});

module.exports = mongoose.model("Employee", employeeSchema);

2-) Parent 参考:

在这个方法中,我们在 Employee 模式中保留评论的引用。 如果您不需要通过评论访问员工,这可以是一个选项。

员工架构:

const mongoose = require("mongoose");

const employeeSchema = new mongoose.Schema({
  firstName: String,
  username: String,
  email: String,
  comments: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Comment"
    }
  ]
});

module.exports = mongoose.model("Employee", employeeSchema);

评论架构:

const mongoose = require("mongoose");

const commentSchema = new mongoose.Schema({
  commentDate: Date,
  comment: String
});

module.exports = mongoose.model("Comment", commentSchema);

3-) Child 引用

在这种方法中,我们在评论中保留对员工的引用。 因此,如果您需要访问员工的评论,我们需要使用 mongoose 的 Populate Virtual 功能。因为在员工模式中我们没有对评论的引用。

员工架构:

const mongoose = require("mongoose");

const employeeSchema = new mongoose.Schema(
  {
    firstName: String,
    username: String,
    email: String
  },
  {
    toJSON: { virtuals: true } // required to use populate virtual
  }
);

// Populate virtual
employeeSchema.virtual("comments", {
  ref: "Comment",
  foreignField: "employee",
  localField: "_id"
});

module.exports = mongoose.model("Employee", employeeSchema);

评论架构:

const mongoose = require("mongoose");

const commentSchema = new mongoose.Schema({
  commentDate: Date,
  comment: String,
  employee: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Employee"
  }
});

module.exports = mongoose.model("Comment", commentSchema);

4-) parent 和 child 均引用:

使用此方法,可以 select 来自员工的评论,以及来自评论的员工。但是这里我们有某种数据重复,而且当评论被删除时,它需要在两个集合中完成。

const mongoose = require("mongoose");

const employeeSchema = new mongoose.Schema({
  firstName: String,
  username: String,
  email: String,
  comments: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Comment"
    }
  ]
});

module.exports = mongoose.model("Employee", employeeSchema);

评论架构:

const mongoose = require("mongoose");

const commentSchema = new mongoose.Schema({
  commentDate: Date,
  comment: String,
  employee: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Employee"
  }
});

module.exports = mongoose.model("Comment", commentSchema);