LiteDB中id的理解与使用

在使用 LiteDB 中,它 Id 规则有些复杂,为了更好地理解,将其总结如下,不足之处,欢迎斧正。

LiteDB 的集合(collection)在存储文档(document)时,文档必需有 _id 字段,因为数据库使用这个字段作为主键,在进行文档更新的时候,也是通过 _id 去匹配更新对象。

在使用中,我们要如何定义 _id 呢?

使用默认 _id

如果在定义类的时候,没有 ID 字段,程序就会自动添加一个 _id,这个 _id 的类型是 ObjectId

此处要注意: ObjectId 在进行 json 序列化时,并不会序列化成字符串,而是序列化为一个 ObjectId 对象,如果将其传到前端,前端对这个 _id 就会非常不方便使用,所以我们一般会指定 _id 字段。

使用 BsonId 定义

我们可以在类中的任意字段添加 BsonId 特性来指定其为 _id,如下例:

1
2
3
4
5
6
7
8
public class User
{
[BsonId]
public string userId { get; set; }
public string password { get; set; }
public DateTime createDate { get; set; }
public string avatar { get; set; }
}

C# 读者请不要在意属性的命名规范问题,本人采用的是 js 的命名风格,方便与 js 前端交互。

上面的定义中,我们在 userId 属性上添加 BsonId 特性,标记该字段作为 User 对象的 _id。数据存储的时候,它会将 userId 保存为 _id 而不是 userId,这一点要特别注意。

截取了实际中的一个对象,其保存的形式如下:

1
2
3
4
5
{
"_id": "admin",
"password": "123456",
"createDate": {"$date": "2021-08-21T13:04:36.6340000Z"}
}

所以,在使用 BsonExpression 的时候,去匹配 userId 需要写成 _id。为了使代码更易理解,建议在类中定义 Id 时,若没有明确的 Id 时,直接命名为 _id

定义递增的 int32 Id

鉴于 ObjecId 对 json 序列化不友好的支持,所以我们希望有一种 _id,它既可以自动添加,又可以 json 序列化成一个字段,而不是像 ObjectId 那样。

这样的 _id 是存在的,就用用 BsonId 对指定一个 int 型的字段,并在任何时候,保证该字段的值为 0。如下所示:

1
2
3
4
5
6
7
8
9
public class User
{
[BsonId]
public int _id { get; set; }
public string userId { get; set; }
public string password { get; set; }
public DateTime createDate { get; set; }
public string avatar { get; set; }
}

此处要注意:

  • _id 的值必须是 0
  • 在实例 User 时,不要对它赋值

这样定义的 _id 就会随着每次 insert 操作而自动增加。即使中间删除了某些数据,它也不会去补充删除的数据,而是在上一条数据的基础上自动增加。

但是,用 int 类型作为 _id 也有一个弊端,因为 int32 的最大值为 65535,集合中的文档总数会有限制。

所以,一般使用下列方式定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class User
{
public User()
{
_id = ObjectId.NewObjectId().ToString();
}

[BsonId]
public string _id { get; set; }
public string userId { get; set; }
public string password { get; set; }
public DateTime createDate { get; set; }
public string avatar { get; set; }
}