Nodejs mongo数据库,自定义id的自增,有方法么

Nodejs mongo数据库,自定义id的自增,有方法么

9 回复

当然可以。在 Node.js 中使用 MongoDB 时,有时我们需要自定义 _id 的生成规则,并且希望这些 _id 是自增的。虽然 MongoDB 本身并不直接支持自增 _id,但我们可以借助一些技巧来实现这一需求。

方法概述

一种常见的方法是在应用层维护一个序列集合(sequence collection),用于存储当前的最大值。每次需要生成新的 _id 时,从该集合中读取当前的最大值并递增,然后将新值写回集合以更新最大值。

示例代码

1. 创建 MongoDB 集合用于存储序列

const mongoose = require('mongoose');

// 定义序列模型
const sequenceSchema = new mongoose.Schema({
    _id: String,
    seq: Number
});

const Sequence = mongoose.model('Sequence', sequenceSchema);

// 初始化序列,如果不存在的话
async function initSequence() {
    try {
        await Sequence.create({ _id: 'customId', seq: 0 });
    } catch (error) {
        if (error.code !== 11000) { // 忽略重复键错误
            throw error;
        }
    }
}

2. 定义生成自增 ID 的函数

async function getNextSequenceValue(sequenceName) {
    const result = await Sequence.findOneAndUpdate(
        { _id: sequenceName },
        { $inc: { seq: 1 } },
        { new: true }
    );
    return result.seq;
}

3. 使用自增 ID 创建文档

const User = mongoose.model('User', new mongoose.Schema({}));

async function createUser(name) {
    const nextId = await getNextSequenceValue('customId');
    const user = new User({
        _id: nextId,
        name: name
    });
    await user.save();
    console.log(`User created with id: ${nextId}`);
}

// 调用示例
initSequence().then(() => createUser('John Doe'));

解释

  • 初始化序列:首先确保有一个序列集合存在,用于存储当前的最大值。
  • 获取下一个序列值getNextSequenceValue 函数负责读取并递增序列值。
  • 创建用户:在创建用户时,我们先获取下一个序列值作为 _id,然后保存用户到数据库中。

这种方法简单且易于理解,但在高并发情况下可能需要额外的锁定机制来避免重复的 _id


现有两个小方法。 第一种是数据库不做物理删除,每条数据再加一个字段标记,删除为1.否则为0.则实际上数据库中的数据没有删除。 第二种是删除正常执行,但执行一次,用变量保存执行次数,返回页面。通过用户操作,再让后台获取。遍历数据库之后,再加上删除的执行次数。完成递增。 还有没有更好一点的办法。求解答

我用的是第一种方法,建一个sequence表用来纪录自增的 id 值

感谢回复

先感谢您的回复,后来想了个稍微简单一点的方法,先根据时间最大找到id,然后id+1作为要插入数据的id。至于删除最大id项后,添加新的时,出现id再次使用,对于我的需求来说,其实无所谓了。

恩,感谢回复。

在Node.js中使用MongoDB时,如果你想为文档生成一个自定义ID并使其自增,这是一个常见的需求。然而,MongoDB本身并不直接支持自增ID功能,因为它的设计初衷是分布式的、高可用的系统,不需要依赖单一的自增序列。

但是,你可以通过一些额外的工作来实现这个功能。这里有几个推荐的方法:

方法1:使用集合中的最大值作为自增ID

这种方法是在插入新文档之前,查询集合中当前的最大_id,然后加1作为新的_id。这种方法适用于单节点的情况,但在分布式环境中可能不太可靠,因为可能会产生冲突。

示例代码:

const MongoClient = require('mongodb').MongoClient;
const url = "mongodb://localhost:27017/";

async function getNextSequenceValue(sequenceName) {
    const client = new MongoClient(url, { useUnifiedTopology: true });
    await client.connect();
    const db = client.db("testdb");
    const sequenceDoc = await db.collection("counters").findOneAndUpdate(
        { _id: sequenceName },
        { $inc: { seq: 1 } },
        { upsert: true, returnDocument: 'after' }
    );
    client.close();
    return sequenceDoc.value.seq;
}

async function insertWithCustomId() {
    const id = await getNextSequenceValue("custom_id");
    const doc = { _id: id, name: "example" };
    const client = new MongoClient(url, { useUnifiedTopology: true });
    await client.connect();
    const db = client.db("testdb");
    await db.collection("documents").insertOne(doc);
    console.log(`Inserted document with custom id ${id}`);
    client.close();
}

insertWithCustomId();

方法2:使用MongoDB的聚合框架

MongoDB 3.4及以上版本提供了更高级的功能,比如聚合框架。可以使用$inc操作符结合聚合框架来生成自增ID。

示例代码:

async function getNextSequenceValue(sequenceName) {
    const client = new MongoClient(url, { useUnifiedTopology: true });
    await client.connect();
    const db = client.db("testdb");
    const result = await db.collection("counters").aggregate([
        { $match: { _id: sequenceName } },
        { $project: { seq: { $add: ["$seq", 1] } } },
        { $merge: { into: "counters", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
    ]).toArray();
    client.close();
    return result[0].seq;
}

注意事项

  • 这些方法都依赖于单点,如果有多台服务器同时生成ID,可能会出现重复。
  • 对于高并发场景,建议使用分布式ID生成器(如Snowflake算法)。
  • 在实际应用中,考虑到性能和可靠性,可能需要更复杂的逻辑来处理ID生成问题。

希望这些建议对你有所帮助!

回到顶部