更改 MongoDB 自然顺序,手动生成 _id 并按 _id 排序,在两行之间插入行实现(React Data Grid)
Change MongoDB natural order, generate _id manually and sort by _id, insert rows between two rows implementation (React Data Grid )
我正在开发一个像 webApp 这样的 Excel,我想实现一个让用户自由插入行的功能。我可以很容易地修改前端以可视化通过拼接和 selected 行 ID 插入的位置,但我们的后端使用 mongoDB 默认生成 _id 和顺序。为了解决这个问题,我们生成了之前和之后的Id,并在之前和之后提出了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初始未定义,单元格selected时setState,行删除后重置为undefined
不过这个算法好像有很多边缘情况没有考虑,有没有人有经验让它更健壮?或者对边缘情况有什么建议吗?
已知问题:
- 当 select 行 [0]
时的错误行为
- 正在生成 dup _id(不知道为什么)
其他想法
- 与其生成_id,不如通过localStorage render 保存用户看到的行状态更容易。
- 我找到了这个 enter link description here 但不明白,谁能解释一下是否有可能的解决方案?
有什么想法吗?
非常感谢
几天后,我找到了这个解决方案。我的方法没有维护 _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 生成方法,我们有限制,两个时间戳至少应该有一个间隔 > 1000,否则会导致问题。
在fetch中我们需要检查是否生成了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 生成器,我们可以不受限制地插入。据我研究,从来没有人想出这样的事情,但我花了几天时间才弄明白。我希望这一发现能为您节省几天的研究时间。
我正在开发一个像 webApp 这样的 Excel,我想实现一个让用户自由插入行的功能。我可以很容易地修改前端以可视化通过拼接和 selected 行 ID 插入的位置,但我们的后端使用 mongoDB 默认生成 _id 和顺序。为了解决这个问题,我们生成了之前和之后的Id,并在之前和之后提出了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初始未定义,单元格selected时setState,行删除后重置为undefined
不过这个算法好像有很多边缘情况没有考虑,有没有人有经验让它更健壮?或者对边缘情况有什么建议吗?
已知问题:
- 当 select 行 [0] 时的错误行为
- 正在生成 dup _id(不知道为什么)
其他想法
- 与其生成_id,不如通过localStorage render 保存用户看到的行状态更容易。
- 我找到了这个 enter link description here 但不明白,谁能解释一下是否有可能的解决方案?
有什么想法吗? 非常感谢
几天后,我找到了这个解决方案。我的方法没有维护 _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 生成方法,我们有限制,两个时间戳至少应该有一个间隔 > 1000,否则会导致问题。
在fetch中我们需要检查是否生成了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 生成器,我们可以不受限制地插入。据我研究,从来没有人想出这样的事情,但我花了几天时间才弄明白。我希望这一发现能为您节省几天的研究时间。