更改MongoDB的自然顺序,手动生成_id并按_id排序,在两行实现之间插入行(React Data Grid)

时间:2019-03-17 07:40:41

标签: reactjs mongodb react-data-grid

我正在使用类似webApp的Excel,并且我想实现一个函数,让用户自由地插入行。我可以轻松地修改前端以通过拼接和选定的行ID可视化插入位置,但是我们的后端使用的是mongoDB,默认情况下会生成_id和顺序。为了解决此问题,我们在Ids之前和之后生成,并在之前和之后之间生成newId。

if (this.state.insertIndex !== undefined && this.state.insertIndex !== 0 && this.state.insertIndex !== rows.length - 1) {
  const after = parseInt(rows[Math.max(this.state.insertIndex - 1, 0)]._id.toString().substring(0, 8), 16) * 1000;
  const before = parseInt(rows[Math.min(this.state.insertIndex + 1, rows.length - 1)]._id.toString().substring(0, 8), 16) * 1000;
  const timestampAsInteger = Math.floor(Math.random() * (after - before) + before);
  newId = Math.floor(timestampAsInteger / 1000).toString(16) + "0000000000000000";
}

注意: insertIndex初始为undefined,在选定单元格时为setState,在行删除后重置为undefined

但是,此算法似乎有许多未考虑的边缘情况,有人有经验使其更加健壮吗?或对边缘案例有何建议?

已知问题:

  • 选择行[0]时行为错误
  • 生成dup _id(不知道为什么)

其他想法

  • 与生成_id相比,通过localStorage呈现保存用户所看到的行状态会更容易。
  • 我发现了这个enter link description here,但不明白,有人可以解释它是否可能解决方案吗?

有什么想法吗? 非常感谢

1 个答案:

答案 0 :(得分:0)

几天后,我讨论了有关解决方案的这项工作。我的方法没有维护_id列表,而是有其局限性。

这是我们根据时间戳前后生成自己的mongo _id的代码

    let newId;
    let canInsert = true;
    if (this.state.insertIndex !== undefined) {
      if (this.state.insertIndex == 0 && rows.length >=2) {
        const before = parseInt(rows[Math.max(this.state.insertIndex, 0)]._id.toString().substring(0, 8), 16) * 1000
        const after = parseInt(rows[Math.min(this.state.insertIndex + 1, rows.length - 1)]._id.toString().substring(0, 8), 16) * 1000;
        if (after - before > 1000) {
          const timestampAsInteger = Math.floor(Math.random() * (after - before + 1) + before);
          if (timestampAsInteger - before > 1000) {
            newId = Math.floor(timestampAsInteger / 1000).toString(16) + "0000000000000000";
          } else {
            canInsert = false;
          }
        } else {
          canInsert = false;
        }
      } else if (this.state.insertIndex < rows.length - 1) {
        const before = parseInt(rows[Math.max(this.state.insertIndex, 0)]._id.toString().substring(0, 8), 16) * 1000
        const after = parseInt(rows[Math.min(this.state.insertIndex + 1, rows.length - 1)]._id.toString().substring(0, 8), 16) * 1000;
        if (after - before > 1000) {
          const timestampAsInteger = Math.floor(Math.random() * (after - before + 1) + before);
          if (timestampAsInteger - before > 1000) {
            newId = Math.floor(timestampAsInteger / 1000).toString(16) + "0000000000000000";
          } else {
            canInsert = false;
          }
        } else {
          canInsert = false;
        }
      }
    }

我理解上面的代码很难阅读,但是特别是由于newId generate方法的缘故,边缘情况很多,我们限制了两个时间戳的间隔至少应大于1000,否则会引起问题。

在获取时,我们需要检查是否生成了newId,否则我们将在最后一行添加

      let index = this.state.insertIndex == undefined? Math.max(rows.length, 0): Math.max(this.state.insertIndex + 1, 0);
      json["value"] = index;
      rows = canInsert ? update(rows, {$splice: [[index, 0, json]]}): update(rows, { $push: [json] });
      if (canInsert) {
        this.showMessage("The project name cannot be empty");
      } else {
        this.showMessage("Impossible to insert, add last instead");
      }

在后端,将_id设置为我们的newId

if (req.body.newId) {
    initialData['_id'] = req.body.newId;
}

此功能最困难的部分是捕获许多可能的边缘情况。并且插入行的局限性在于,两个现有行可能不会产生太紧密的关系。如果该应用程序不断扩大与更多用户的接触,就会出现问题。但是它将适用于较小的用户群,并且在需要时作为可选功能。

将来,如果我们能提供一个更独特的id生成器,我们也许可以无限制地插入它。据我研究,没有人想到过这样的事情,但是花了我几天的时间才弄清楚。希望这项发现可以为您节省研究时间。