MongoDB 术语、安装及依赖
本章我们讨论 MongoDB 的术语、安装及 Rust 操作 MongoDB 的依赖。MongoDB 插入数据
本章我们将讨论 MongoDB 插入数据的方法。MongoDB 查询数据
本章将讨论 MongoDB 查询全部数据、查询单条数据以及分页显示的方法。MongoDB 修改数据
本章将讨论 MongoDB 修改已有数据、替换已有数据、修改或插入新数据的方法。MongoDB 删除记录
本章将讨论 Mongo DB 删除记录操作MongoDB 过滤
本章将讨论 MongoDB 中最常用的功能:过滤器的定义。MongoDB 聚合操作
本章将讨论 MongoDB 的两种聚合操作:单一聚合和聚合管道。
MongoDB 插入数据
- 12
- 2025-06-06 16:32:57
本章我们将讨论 MongoDB 插入数据的方法。
模型定义
使用自定义ID
MongoDB 使用 _id
字段作为主键来标识不同的文档(document,对应关系型数据库中的“记录”):
-
如果未显式指定
_id
字段的值,MongDB 会自动分配全局唯一的ObjectId
#[derive(Debug, Serialize, Deserialize)] pub struct Note { #[serde(rename = "_id")] pub id: mongodb::bson::oid::ObjectId, pub title: String, pub content: String, }
-
我们可以自定义
_id
字段的值,比如使用 xid#[derive(Debug, Serialize, Deserialize)] pub struct Note { #[serde(rename = "_id")] pub id: String, pub title: String, pub content: String, }
-
尽量不要使用关系型数据库中整数型自动编号。虽然 MongoDB 只认
_id
字段,而不区分它的数据类型,但由于 MongoDB 天生为集群设计的,所以为了避免扩展时出现主键冲突,不建议使用自动编号作为主键值。
日期时间的处理
我们需要安装带有 chrono-0_4
feature 的 bson
,利用它提供 bson::serde_helpers::chrono_datetime_as_bson_datetime
转换函数将 chrono 的日期时间值转换为 MongDB bson 所需要的格式:
#[derive(Debug, Serialize, Deserialize)]
pub struct Note {
#[serde(rename = "_id")]
pub id: String,
pub title: String,
pub content: String,
#[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
pub created_at: chrono::DateTime<chrono::Utc>,
}
如果你使用的是标准库的日期时间,则可以使用
mongodb
crate 带的转换函数
模型方法
为了方便操作,我们给这个模型定义 new()
方法:
impl Note {
pub fn new(title: impl Into<String>, content: impl Into<String>) -> Self {
Self {
id: xid::new().to_string(),
title: title.into(),
content: content.into(),
created_at: chrono::Utc::now(),
}
}
}
数据库连接
- 使用
Client
连接到 MongoDB 服务器 - 然后使用
Client
的database()
方法,选择数据库。该方法返回的是一个Database
实例 - 在 Axum 中,通过
with_state()
来共享Database
实例 Client
和Database
内部都使用了Arc
,所以它们都是并发安全的,并且可以低成本地进行Clone
操作
文档定义
和关系型数据库不同,我们需要为 MongoDB 的每个文档进行定义,它由 Database
的 collect()
方法提供,它返回的是一个 Collect<T>
结构体。
为了方便操作,我们在共享状态中定义了获取文档的方法:
pub struct AppState {
pub db: mongodb::Database,
}
impl AppState {
pub fn collect<T>(&self, name: &str) -> mongodb::Collection<T>
where
T: Send + Sync,
{
self.db.collection(name)
}
pub fn note_collect(&self) -> mongodb::Collection<crate::model::Note> {
self.collect("note")
}
}
pub type ArcAppState = std::sync::Arc<AppState>;
- 共享状态维护了 MongoDB 数据库连接
collect<T>()
方法用于从数据库连接中获取集合- 调用的其实是 MongoDB 的
Database
提供的同名方法 - 泛型
T
指向的是我们的模型 - 参数
name
指向的是集合的名称
- 调用的其实是 MongoDB 的
note_collect()
方法用于从数据库连接中,获取笔记的集合
MongoDB 的 Collection
提供了多种插入文档的方法,其中 insert_one()
用于插入单个文档到集合中:
pub async fn insert(
State(state): State<ArcAppState>,
Json(frm): Json<form::CreateNote>,
) -> Result<Json<String>> {
let note = model::Note::new(frm.title, frm.content);
state.note_collect().insert_one(¬e).await?;
Ok(Json(note.id))
}
测试:
## 插入单条笔记
POST http://127.0.0.1:9527
Content-Type: application/json
{
"title":"foo",
"content":"bar"
}
结果:
⚠️ 在 MongoDB 中,如果数据库、集合不存在,那么在执行插入时,MongoDB 服务器会自动创建。
插入多条记录
MongoDB 还提供了 insert_many()
方法,用于向集合中插入多个文档:
pub async fn insert_many(
State(state): State<ArcAppState>,
Json(frm): Json<Vec<form::CreateNote>>,
) -> Result<Json<Vec<String>>> {
let notes = frm
.into_iter()
.map(|f| model::Note::new(f.title, f.content))
.collect::<Vec<_>>();
state.note_collect().insert_many(¬es).await?;
Ok(Json(notes.into_iter().map(|n| n.id).collect()))
}
测试:
## 插入多条笔记
POST http://127.0.0.1:9527/many
Content-Type: application/json
[
{
"title":"note1",
"content":"笔记1"
},
{
"title":"note2",
"content":"笔记2"
},
{
"title":"note3",
"content":"笔记3"
}
]
结果:
HTTP/1.1 200 OK
content-type: application/json
content-length: 70
connection: close
date: Wed, 04 Jun 2025 08:51:18 GMT
[
"d100i1kdrfaihab7dmig",
"d100i1kdrfaihab7dmj0",
"d100i1kdrfaihab7dmjg"
]