在MongoDB中跟踪文档属性更改的最佳方法是什么?

时间:2019-08-30 01:22:50

标签: javascript node.js reactjs mongodb backend

我想知道如何在MongoDB中跟踪文档的值。

这是一个具有Node和Express后端的MongoDB数据库。

说我有一个文档,它是“患者”合集中的一部分。

{
    "_id": "4k2lK49938d82kL",
    "firstName": "John",
    "objective": "Burn fat"
}

然后我编辑“目标”属性,因此文档结果如下:

{
    "_id": "4k2lK49938d82kL",
    "firstName": "John",
    "objective": "Gain muscle"
}

跟踪变化的最佳/最有效方法是什么?换句话说,我想知道“客观”属性在过去具有“燃烧脂肪”的值,并在将来使用它。

非常感谢!

4 个答案:

答案 0 :(得分:0)

将其维护为如下所示的子文档

{
    "_id": "4k2lK49938d82kL",
    "firstName": "John",
    "objective": {
        obj1: "Gain muscle",
        obj2: "Burn fat"
    }

}

您也可以将其维护为数组字段,但是请记住,mongodb不允许您在数组字段中保持唯一性,如果您计划对“目标”字段建立索引,则必须创建一个多键索引

答案 1 :(得分:0)

也许您可以将“目标”的类型更改为数组并跟踪其中的更改。数组的最后一个是最新值。

答案 2 :(得分:0)

我认为最简单的解决方案是使用和更新数组:

const patientSchema = new Schema({
  firstName: { type: String, required: true },
  lastName: { type: String, required: true },
  objective: { type: String, required: true }
  notes: [{
    date: { type: Date, default: Date.now() },
    note: { type: String, required: true }
  }],
});

然后,当您要更新目标时...

const updatePatientObjective = async (req, res) => {
  try {
    // check if _id and new objective exist in req.body
    const { _id, objective, date } = req.body;
    if (!_id || !objective) throw "Unable to update patient's objective.";

    // make sure provided _id is valid
    const existingPatient = await Patient.findOne({ _id });
    if (!existingPatient) throw "Unable to locate that patient.";

    // pull out objective as previousObjective 
    const { objective: previousObjective } = existingPatient;

    // update patient's objective while pushing 
    // the previous objective into the notes sub document
    await existingPatient.updateOne({ 
        // update current objective
        $set { objective },
        // push an object with a date and note (previouseObjective) 
        // into a notes array
        $push: { 
          notes: {
            date,
            note: previousObjective              
         },
        },  
      }),
    );

    // send back response
    res
      .status(201)
      .json({ message: "Successfully updated your objective!" });
  } catch (err) {
    return res.status(400).json({ err: err.toString() });
  }
};

文档外观如下:

firstName: "John",
lastName: "Smith",
objective: "Lose body fat.",
notes: [
  {
    date: 2019-07-19T17:45:43-07:00,
    note: "Gain muscle".
  },
  { 
    date: 2019-08-09T12:00:38-07:00,
    note: "Work on cardio."
  }
  { 
    date: 2019-08-29T19:00:38-07:00,
    note: "Become a fullstack web developer."
  }
  ...etc
]

或者,如果您担心文档的大小,则可以为患者历史记录创建一个单独的架构,并引用用户的ID(或者将患者的_id存储为字符串,而不是引用ObjectId(随便使用哪个对象)):

const patientHistorySchema = new Schema({
  _id: { type: Schema.Types.ObjectId, ref: "Patient", required: true },
  objective: { type: String, required: true }
});

然后在目标更新时创建一个新的患者历史记录文档...

PatientHistory.create({ _id, objective: previousObjective });

如果您需要访问患者历史记录文档...

PatientHistory.find({ _id });

答案 3 :(得分:0)

并非所有建议都维护/跟踪同一文档中的历史记录。由于文档的大小将不断增加,导致

  • 如果更新太多,文档大小限制为16mb
  • 性能下降

相反,您应该维护一个单独的历史记录集合。您可能使用过休眠的Javers或envers来审核关系数据库。如果没有,您可以检查它们的工作方式。每个表(xyz)维护一个单独的表(xyz_AUD)。对于xyz表中的每一行(具有主键abc),xyz_AUD表中都存在多行,其中每一行都是该行的版本。

此外,Javers还支持MongoDB审核。如果您使用的是Java,则可以直接使用它。无需编写自己的逻辑。

引荐-here

Javers Envers Hibernate是Java库。但是我敢肯定,对于其他编程语言,也会有类似的库。

还有一个猫鼬插件-