MongoDB JavaScript 教程
最后修改于 2023 年 10 月 18 日
本文档展示了如何使用 JavaScript 编写与 MongoDB 交互的程序。本教程使用原生的 mongodb 驱动程序。(也有其他解决方案,如 Mongoose 或 Monk。)
MongoDB
MongoDB 是一个 NoSQL 跨平台面向文档的数据库。它是目前最流行的数据库之一。MongoDB 由 MongoDB Inc. 开发,并作为免费和开源软件发布。
MongoDB 中的一个记录是文档,它是由字段和值对组成的数据结构。MongoDB 文档与 JSON 对象相似。字段的值可能包含其他文档、数组以及文档数组。MongoDB 将文档存储在集合中。集合类似于关系数据库中的表,文档类似于行。
安装 MongoDB 服务器
以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。
$ sudo apt-get install mongodb
该命令安装 MongoDB 附带的必要软件包。
$ sudo service mongodb status mongodb start/running, process 975
使用 sudo service mongodb status 命令,我们检查 mongodb 服务器的状态。
$ sudo service mongodb start mongodb start/running, process 6448
mongodb 服务器通过 sudo service mongodb start 命令启动。
安装 MongoDB 驱动程序
我们来设置项目。
$ npm i mongodb
我们安装 mongodb 原生 JavaScript 驱动程序。npm 是 Node.js 的包管理器。MongoDB Node.js 驱动程序同时提供了基于回调和基于 Promise 的交互方式。
MongoDB 创建数据库
mongo 工具是一个与 MongoDB 交互的 JavaScript shell 界面,它为系统管理员提供了一个接口,也为开发人员提供了一种直接与数据库测试查询和操作的方式。
$ mongo testdb
MongoDB shell version v4.0.7
...
> db
testdb
> db.cars.insert({name: "Audi", price: 52642})
> db.cars.insert({name: "Mercedes", price: 57127})
> db.cars.insert({name: "Skoda", price: 9000})
> db.cars.insert({name: "Volvo", price: 29000})
> db.cars.insert({name: "Bentley", price: 350000})
> db.cars.insert({name: "Citroen", price: 21000})
> db.cars.insert({name: "Hummer", price: 41400})
> db.cars.insert({name: "Volkswagen", price: 21600})
我们创建一个 testdb 数据库,并在 cars 集合中插入八个文档。
MongoDB Promise
Promise 是一个用于延迟和异步计算的对象。它表示一个尚未完成但预计将在未来完成的操作。
asyncFunc()
.then(value => { /* success */ })
.catch(error => { /* failure */ })
.finally( => { /* cleanup */};
then 方法总是返回一个 Promise,这使我们能够链式调用方法。
MongoClient 的 connect 方法将返回一个 Promise。我们也可以使用 async/await 语法来处理 Promise。
MongoDB JS 驱动程序
在第一个示例中,我们打印 Node.js 驱动程序的版本。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
console.log(client.topology.clientInfo);
client.close();
});
在示例中,我们连接到服务器并查找客户端信息。
const mongo = require('mongodb');
我们使用 mongodb 模块。
const client = mongo.MongoClient;
MongoClient 用于连接到 MongoDB 服务器。
const url = 'mongodb://:27017';
这是数据库的 URL。27017 是 MongoDB 服务器监听的默认端口。
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
使用 connect 创建到数据库的连接。
$ node driver_version.js
{ driver: { name: 'nodejs', version: '3.2.2' },
os:
{ type: 'Windows_NT',
name: 'win32',
architecture: 'x64',
version: '10.0.17134' },
platform: 'Node.js v11.5.0, LE' }
驱动程序版本为 3.2.2。
MongoDB 列出数据库集合
listCollections 方法列出数据库中可用的集合。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.listCollections().toArray().then((docs) => {
console.log('Available collections:');
docs.forEach((doc, idx, array) => { console.log(doc.name) });
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例连接到 testdb 数据库并检索其所有集合。
db.listCollections().toArray().then((docs) => {
console.log('Available collections:');
docs.forEach((doc, idx, array) => { console.log(doc.name) });
...
listCollection 方法查找 testdb 数据库中的所有集合;它们会被打印到控制台。
toArray 方法,因为它可能导致大量内存占用。}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
在 catch 块中,我们捕获任何潜在的异常,并在 finally 块中关闭到数据库的连接。
$ node list_collections.js Available collections: continents cars cities
在我们的数据库中,有这三个集合。
MongoDB 数据库统计信息
dbstats 方法获取数据库的统计信息。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.stats((err, stats) => {
if (err) throw err;
console.log(stats);
client.close();
})
});
该示例连接到 testdb 数据库并显示其统计信息。
$ node dbstats.js
{ db: 'testdb',
collections: 3,
views: 0,
objects: 18,
avgObjSize: 57.888888888888886,
dataSize: 1042,
storageSize: 69632,
numExtents: 0,
indexes: 3,
indexSize: 69632,
fsUsedSize: 136856346624,
fsTotalSize: 254721126400,
ok: 1 }
MongoDB find
find 函数创建一个用于查询的游标,该游标可用于迭代 MongoDB 的结果。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
在示例中,我们从 cars 集合中检索所有文档。
db.collection('cars').find({}).toArray().then((docs) => {
传递一个空查询会返回所有文档。
$ node find_all.js
[ { _id: 5cfcfc3438f62aaa09b52175, name: 'Audi', price: 52642 },
{ _id: 5cfcfc3a38f62aaa09b52176, name: 'Mercedes', price: 57127 },
{ _id: 5cfcfc3f38f62aaa09b52177, name: 'Skoda', price: 9000 },
{ _id: 5cfcfc4338f62aaa09b52178, name: 'Volvo', price: 29000 },
{ _id: 5cfcfc4838f62aaa09b52179, name: 'Bentley', price: 350000 },
{ _id: 5cfcfc4b38f62aaa09b5217a, name: 'Citroen', price: 21000 },
{ _id: 5cfcfc4f38f62aaa09b5217b, name: 'Hummer', price: 41400 },
{ _id: 5cfcfc5438f62aaa09b5217c,
name: 'Volkswagen',
price: 21600 } ]
MongoDB 计数文档
count 函数返回集合中匹配文档的数量。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).count().then((n) => {
console.log(`There are ${n} documents`);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算 cars 集合中文档的数量。
$ node count_documents.js There are 8 documents
现在 cars 集合中有八个文档。
MongoDB findOne
findOne 方法返回一个满足指定查询条件的文档。如果多个文档满足查询,则此方法根据自然顺序返回第一个文档,该顺序反映了文档在磁盘上的顺序。
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let collection = db.collection('cars');
let query = { name: 'Volkswagen' }
collection.findOne(query).then(doc => {
console.log(doc);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从 cars 集合中读取一个文档。
let query = { name: 'Volkswagen' }
查询包含汽车的名称——大众。
collection.findOne(query).then(doc => {
查询被传递给 findOne 方法。
$ node find_one.js
{ _id: 8, name: 'Volkswagen', price: 21600 }
MongoDB async/await 示例
使用 async/await,我们可以以同步的方式轻松处理 Promise。
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://:27017';
async function findCar() {
const client = await MongoClient.connect(url, { useNewUrlParser: true })
.catch(err => { console.log(err); });
if (!client) {
return;
}
try {
const db = client.db("testdb");
let collection = db.collection('cars');
let query = { name: 'Volkswagen' }
let res = await collection.findOne(query);
console.log(res);
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
findCar();
该示例使用 async/await 读取一个文档。
async function findCar() {
该函数带有 async 关键字。
let res = await collection.findOne(query);
使用 await,我们等待 findOne 函数的结果。
MongoDB 查询运算符
可以使用 $gt、$lt 或 $ne 等 MongoDB 查询运算符来过滤数据。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { price: { $gt: 30000 } };
db.collection('cars').find(query).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例打印所有汽车价格大于 30,000 的文档。
let query = { price: { $gts: 30000 } };
使用 $gt 运算符来获取价格大于 30,000 的汽车。
$ node read_gt.js
[ { _id: 5d03e40536943362cffc84a7, name: 'Audi', price: 52642 },
{ _id: 5d03e40a36943362cffc84a8, name: 'Mercedes', price: 57127 },
{ _id: 5d03e41936943362cffc84ab, name: 'Bentley', price: 350000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 } ]
这是示例的输出。只包含价格超过 30,000 的汽车。
$and 逻辑运算符可用于组合多个表达式。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { $and: [{ price: { $gt: 20000 } }, { price: { $lt: 50000 } }] };
db.collection('cars').find(query).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
在示例中,我们检索价格在 20,000 到 50,000 之间的汽车。
let query = { $and: [{ price: { $gt: 20000 } }, { price: { $lt: 50000 } }] };
$and 运算符结合 $gt 和 $lt 来获取结果。
$ node read_gt_lt.js
[ { _id: 5d03e41336943362cffc84aa, name: 'Volvo', price: 29000 },
{ _id: 5d03e41e36943362cffc84ac, name: 'Citroen', price: 21000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 },
{ _id: 5d03e42636943362cffc84ae,
name: 'Volkswagen',
price: 21600 } ]
MongoDB 投影
投影决定了从数据库中传递哪些字段。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).project({_id: 0}).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从输出中排除了 _id 字段。
db.collection('cars').find({}).project({_id: 0}).toArray().then((docs) => {
project 方法为查询设置投影;它排除了 _id 字段。
$ node projections.js
[ { name: 'Audi', price: 52642 },
{ name: 'Mercedes', price: 57127 },
{ name: 'Skoda', price: 9000 },
{ name: 'Volvo', price: 29000 },
{ name: 'Bentley', price: 350000 },
{ name: 'Citroen', price: 21000 },
{ name: 'Hummer', price: 41400 },
{ name: 'Volkswagen', price: 21600 } ]
这是示例的输出。
MongoDB 限制数据输出
limit 方法指定要返回的文档数量,skip 方法指定要跳过的文档数量。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).skip(2).limit(5).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从 cars 集合中读取,跳过前两个文档,并将输出限制为五个文档。
db.collection('cars').find({}).skip(2).limit(5).toArray().then((docs) => {
skip 方法跳过前两个文档,limit 方法将输出限制为五个文档。
$ node skip_limit.js
[ { _id: 5d03e40f36943362cffc84a9, name: 'Skoda', price: 9000 },
{ _id: 5d03e41336943362cffc84aa, name: 'Volvo', price: 29000 },
{ _id: 5d03e41936943362cffc84ab, name: 'Bentley', price: 350000 },
{ _id: 5d03e41e36943362cffc84ac, name: 'Citroen', price: 21000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 } ]
MongoDB 聚合
聚合计算集合中数据的聚合值。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let myagr = [{$group: {_id: 1, all: { $sum: "$price" } }}];
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
console.log(sum);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算集合中所有汽车的价格。
let myagr = [{$group: {_id: 1, all: { $sum: "$price" } }}];
$sum 运算符计算并返回数值的总和。$group 运算符根据指定的标识符表达式对输入文档进行分组,并对每个组应用指定的累加器表达式。$sum 运算符用于计数。
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
aggregate 函数对 cars 集合应用聚合操作。
$ node sum_all_cars.js
[ { _id: 1, all: 581769 } ]
所有价格的总和为 581,769。
我们可以使用 $match 运算符来选择要聚合的特定汽车。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let myagr = [
{ $match: { $or: [{ name: "Audi" }, { name: "Volvo" }] } },
{ $group: { _id: 1, sum2cars: { $sum: "$price" } } }
];
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
console.log(sum);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算奥迪和沃尔沃汽车价格的总和。
let myagr = [
{ $match: { $or: [{ name: "Audi" }, { name: "Volvo" }] } },
{ $group: { _id: 1, sum2cars: { $sum: "$price" } } }
];
该表达式使用 $match、$or、$group 和 $sum 运算符来完成任务。
$ node sum_two_cars.js
[ { _id: 1, sum2cars: 81642 } ]
这两辆车的价格总和为 81,642。
MongoDB insertOne
insertOne 方法将单个文档插入到集合中。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const ObjectID = mongo.ObjectID;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let doc = {_id: new ObjectID(), name: "Toyota", price: 37600 };
db.collection('cars').insertOne(doc).then((doc) => {
console.log('Car inserted')
console.log(doc);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例将一辆汽车插入到 cars 集合中。
let doc = {_id: new ObjectID(), name: "Toyota", price: 37600 };
这是一个要插入的文档。使用 ObjectID 生成一个新 ID。
db.collection('cars').insertOne(doc).then((doc) => {
insertOne 函数将文档插入到集合中。
> db.cars.find({name:'Toyota'})
{ "_id" : ObjectId("5d03d4321f9c262a50e671ee"), "name" : "Toyota", "price" : 37600 }
我们使用 mongo 工具确认插入。
MongoDB insertMany
insertMany 函数将多个文档插入到集合中。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const ObjectID = mongo.ObjectID;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let collection = db.collection('continents');
let continents = [
{ _id: new ObjectID(), name: "Africa" }, { _id: new ObjectID(), name: "America" },
{ _id: new ObjectID(), name: "Europe" }, { _id: new ObjectID(), name: "Asia" },
{ _id: new ObjectID(), name: "Australia" }, { _id: new ObjectID(), name: "Antarctica" }
];
collection.insertMany(continents).then(result => {
console.log("documents inserted into the collection");
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例创建一个 continents 集合并向其中插入六个文档。
let collection = db.collection('continents');
collection 方法检索一个集合;如果集合不存在,则会创建它。
let continents = [
{ _id: new ObjectID(), name: "Africa" }, { _id: new ObjectID(), name: "America" },
{ _id: new ObjectID(), name: "Europe" }, { _id: new ObjectID(), name: "Asia" },
{ _id: new ObjectID(), name: "Australia" }, { _id: new ObjectID(), name: "Antarctica" }
];
这是一个要插入到新集合中的六条记录的数组。ObjectID 创建一个新的 ObjectID,这是一个唯一值,用于标识文档而不是整数。
collection.insertMany(continents).then(result => {
console.log("documents inserted into the collection");
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
insertMany 方法将文档数组插入到 continents 集合中。
> db.continents.find()
{ "_id" : ObjectId("5cfcf97732fc4913748c9669"), "name" : "Africa" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966a"), "name" : "America" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966b"), "name" : "Europe" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966c"), "name" : "Asia" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966d"), "name" : "Australia" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966e"), "name" : "Antarctica" }
continents 集合已成功创建。
MongoDB deleteOne
deleteOne 方法用于删除一个文档。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { name: "Volkswagen" };
db.collection('cars').deleteOne(query).then((result) => {
console.log('Car deleted');
console.log(result);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例删除一个文档。
let query = { name: "Volkswagen" };
db.collection('cars').deleteOne(query).then((result) => {
...
deleteOne 删除大众汽车的文档。
MongoDB updateOne
updateOne 函数用于更新文档。
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let filQuery = { name: "Audi" };
let updateQuery = { $set: { "price": 52000 }};
db.collection('cars').updateOne(filQuery, updateQuery).then(result => {
console.log('Car updated');
console.log(result);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例更新汽车的价格。
let filQuery = { name: "Audi" };
let updateQuery = { $set: { "price": 52000 }};
db.collection('cars').updateOne(filQuery, updateQuery).then(result => {
使用 updateOne 方法将奥迪的价格更改为 52,000。使用 $set 运算符来更改价格。
> db.cars.find({name:'Audi'})
{ "_id" : ObjectId("5cfcfc3438f62aaa09b52175"), "name" : "Audi", "price" : 52000 }
我们使用 mongo 工具确认更改。
来源
在本文档中,我们使用 MongoDB 和 JavaScript 进行了一些操作。