MongoDB自增ID在golang中的实践
文章发布较早,内容可能过时,阅读注意甄别。
MongoDB 默认的 ID 不像 MySQL 那样的自增 ID,如果想要实现自增 ID,则需要借助于另一张表存放该表的 ID,每次存数据的时候,需要通过 findAndModify 方法对这个 ID 进行获取并加 1。
# 原生 MongoDB 语句
$ db.ids.save({name:"user", next_id:NumberInt("0")});
1
创建一个集合,专门存储其他表的自增信息,默认数字类型是int64
,这里通过NumberInt()
方法将其指定为int32
。
查询该条记录:
$ db.getCollection('ids').find({})
{
"_id" : ObjectId("6234313fb503f6bf2433f4e4"),
"name" : "user",
"next_id" : 0
}
1
2
3
4
5
6
2
3
4
5
6
新增用户的时候,直接调用获取 ID:
$ db.user.save({
_id: NumberInt(db.ids.findAndModify({
update:{$inc:{'next_id':NumberInt("1")}},
query:{"name":"user"},
new:true
}).next_id),
username: "eryajf",
site:"https://wiki.eryajf.net"
});
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
注:
因为 findAndModify 是一个方法完成更新查找两个操作,所以具有原子性,多线程不会冲突。
然后查询该条记录:
$ db.getCollection('user').find({})
{
"_id" : 1,
"username" : "eryajf",
"site" : "https://wiki.eryajf.net"
}
1
2
3
4
5
6
2
3
4
5
6
# golang 的实现
golang 的实现与语句差不多,这里只是做示例展示,其中的GetDataID("user")
在实际生产使用过程中,需要确保对其错误进行处理。
package main
import (
"context"
"fmt"
"learnmongo/public"
"log"
"math/rand"
"strconv"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var DB *mongo.Database
func init() {
uri := "mongodb://root:123456@10.1.1.3:27017"
if uri == "" {
log.Fatal("You must set your 'MONGODB_URI' environmental variable. See\n\t https://docs.mongodb.com/drivers/go/current/usage-examples/#environment-variable")
}
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
panic(err)
}
DB = client.Database("class")
}
type UserMongo struct {
ID int32 `bson:"_id"`
Name string `bson:"name"`
Phone string `bson:"phone"`
Email string `bson:"email"`
}
func main() {
defer func() {
if err := public.InitDb().Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
fmt.Println("start")
table := DB.Collection("user") // 指定表名为user
_, err := table.InsertMany(context.TODO(), []interface{}{
UserMongo{
ID: GetDataID("user"),
Name: "eryajf" + strconv.Itoa(rand.Intn(11)),
Phone: strconv.Itoa(rand.Intn(11)),
Email: strconv.Itoa(rand.Intn(5)) + "@qq.com",
},
UserMongo{
ID: GetDataID("user"),
Name: "liql" + strconv.Itoa(rand.Intn(11)),
Phone: strconv.Itoa(rand.Intn(11)),
Email: strconv.Itoa(rand.Intn(5)) + "@qq.com",
},
})
if err != nil {
fmt.Print(err)
return
}
fmt.Println("end「👋」")
}
func GetDataID(collname string) int32 {
table := DB.Collection("ids") // 指定表名为ids表
var result struct {
Name string `json:"name" bson:"name"`
NextID int32 `json:"next_id" bson:"next_id"`
}
table.FindOneAndUpdate(
context.TODO(),
bson.M{"name": collname},
bson.M{"$inc": bson.M{"next_id": 1}}).Decode(&result)
return result.NextID
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
自增 ID 从视觉上更加直观,与 DB 交互查询的时候也更加简便,某些场景中是可取的方案。
上次更新: 2024/11/19, 23:11:42