在MongoDB中,引用(Reference)是一种在文档之间建立关系的方式。与嵌入式文档不同,引用是通过存储其他集合中文档的标识符来建立关系。这种方式类似于SQL中的外键,适用于需要多个独立集合之间建立关系的场景。
引用的特点
- 分离数据:引用将相关数据分离到不同的集合中,有助于减少数据冗余。
- 独立更新:引用允许独立更新相关数据,而不需要更新整个文档。
- 适合一对多和多对多关系:引用特别适用于复杂的数据模型,比如一对多和多对多关系。
使用引用的示例
以下示例展示了如何在MongoDB中使用引用。我们将使用Node.js和MongoDB的驱动进行操作。
安装MongoDB的Node.js驱动
bash
npm install mongodb
插入包含引用的数据
javascript
const { MongoClient, ObjectId } = require('mongodb');
async function insertData() {
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useUnifiedTopology: true });
try {
await client.connect();
const db = client.db('myDatabase');
const usersCollection = db.collection('users');
const ordersCollection = db.collection('orders');
await usersCollection.deleteMany({}); // 清空用户集合
await ordersCollection.deleteMany({}); // 清空订单集合
// 插入用户数据
const users = await usersCollection.insertMany([
{ name: "Alice" },
{ name: "Bob" },
{ name: "Charlie" }
]);
// 插入订单数据,并使用用户的ObjectId作为引用
await ordersCollection.insertMany([
{ userId: users.insertedIds[0], amount: 50.5, date: new Date("2022-01-01") },
{ userId: users.insertedIds[0], amount: 100.0, date: new Date("2022-02-01") },
{ userId: users.insertedIds[1], amount: 75.0, date: new Date("2022-01-15") },
{ userId: users.insertedIds[2], amount: 200.0, date: new Date("2022-03-01") }
]);
console.log("Data inserted");
} finally {
await client.close();
}
}
insertData().catch(console.error);
在上面的代码中,orders 集合中的每个文档都包含一个 userId 字段,该字段引用了 users 集合中的用户文档的 _id。
查询包含引用的数据
javascript
async function queryData() {
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useUnifiedTopology: true });
try {
await client.connect();
const db = client.db('myDatabase');
const usersCollection = db.collection('users');
const ordersCollection = db.collection('orders');
// 查询某个用户及其所有订单
console.log("\nQuery a user and their orders:");
let user = await usersCollection.findOne({ name: "Alice" });
let orders = await ordersCollection.find({ userId: user._id }).toArray();
console.log({ user, orders });
// 查询所有订单及其对应的用户信息
console.log("\nQuery all orders and their corresponding users:");
let results = await ordersCollection.aggregate([
{
$lookup: {
from: 'users', // 要关联的集合
localField: 'userId', // orders 集合中的字段
foreignField: '_id', // users 集合中的字段
as: 'user' // 输出数组字段
}
},
{
$unwind: '$user' // 展开数组
}
]).toArray();
console.log(results);
} finally {
await client.close();
}
}
queryData().catch(console.error);
在这个示例中,我们演示了如何查询包含引用的数据:
- 查询某个用户及其所有订单。
- 查询所有订单及其对应的用户信息。
运行这个脚本后,你会得到如下结果(示例输出):
javascript
// 查询某个用户及其所有订单
Query a user and their orders:
{
user: { _id: new ObjectId("..."), name: 'Alice' },
orders: [
{ _id: new ObjectId("..."), userId: new ObjectId("..."), amount: 50.5, date: 2022-01-01T00:00:00.000Z },
{ _id: new ObjectId("..."), userId: new ObjectId("..."), amount: 100, date: 2022-02-01T00:00:00.000Z }
]
}
// 查询所有订单及其对应的用户信息
Query all orders and their corresponding users:
[
{
_id: new ObjectId("..."),
userId: new ObjectId("..."),
amount: 50.5,
date: 2022-01-01T00:00:00.000Z,
user: { _id: new ObjectId("..."), name: 'Alice' }
},
{
_id: new ObjectId("..."),
userId: new ObjectId("..."),
amount: 100,
date: 2022-02-01T00:00:00.000Z,
user: { _id: new ObjectId("..."), name: 'Alice' }
},
{
_id: new ObjectId("..."),
userId: new ObjectId("..."),
amount: 75,
date: 2022-01-15T00:00:00.000Z,
user: { _id: new ObjectId("..."), name: 'Bob' }
},
{
_id: new ObjectId("..."),
userId: new ObjectId("..."),
amount: 200,
date: 2022-03-01T00:00:00.000Z,
user: { _id: new ObjectId("..."), name: 'Charlie' }
}
]
其他语言示例
类似的操作可以在其他编程语言中实现,如Python。以下是Python的示例代码:
安装PyMongo
在终端中运行以下命令来安装PyMongo:
bash
pip install pymongo
插入数据
python
from pymongo import MongoClient
from datetime import datetime
def insert_data():
client = MongoClient('mongodb://localhost:27017/')
db = client['myDatabase']
users_collection = db['users']
orders_collection = db['orders']
users_collection.delete_many({}) # 清空用户集合
orders_collection.delete_many({}) # 清空订单集合
# 插入用户数据
users = users_collection.insert_many([
{ "name": "Alice" },
{ "name": "Bob" },
{ "name": "Charlie" }
])
# 插入订单数据,并使用用户的ObjectId作为引用
orders_collection.insert_many([
{ "userId": users.inserted_ids[0], "amount": 50.5, "date": datetime(2022, 1, 1) },
{ "userId": users.inserted_ids[0], "amount": 100.0, "date": datetime(2022, 2, 1) },
{ "userId": users.inserted_ids[1], "amount": 75.0, "date": datetime(2022, 1, 15) },
{ "userId": users.inserted_ids[2], "amount": 200.0, "date": datetime(2022, 3, 1) }
])
print("Data inserted")
insert_data()
查询数据
python
def query_data():
client = MongoClient('mongodb://localhost:27017/')
db = client['myDatabase']
users_collection = db['users']
orders_collection = db['orders']
# 查询某个用户及其所有订单
print("\nQuery a user and their orders:")
user = users_collection.find_one({ "name": "Alice" })
orders = list(orders_collection.find({ "userId": user['_id'] }))
print({ "user": user, "orders": orders })
# 查询所有订单及其对应的用户信息
print("\nQuery all orders and their corresponding users:")
pipeline = [
{
'$lookup': {
'from': 'users', # 要关联的集合
'localField': 'userId', # orders 集合中的字段
'foreignField': '_id', # users 集合中的字段
'as': 'user' # 输出数组字段
}
},
{
'$unwind': '$user' # 展开数组
}
]
results = list(orders_collection.aggregate(pipeline))
for result in results:
print(result)
query_data()