本文主要讲node是如何连接mongodb,并做基本的增删改查操作
mongodb的安装不多赘述,可参考菜鸟教程
mongodb与mysl的性能分析
本文参考地址: https://github.com/mongodb/node-mongodb-native
官方API文档:https://mongodb.github.io/node-mongodb-native/3.0/api/
本文项目环境: ubuntu16.04 [email protected] [email protected]
mkdir test_mongodb
npm init
npm install mongodb --save
mongod --dbpath=/data
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
client.close();
});
执行命令可检测是否连接成功
node app.js
const insertDocuments = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Insert some documents
collection.insertMany([
{a : 1}, {a : 2}, {a : 3}
], function(err, result) {
assert.equal(err, null);
assert.equal(3, result.result.n);
assert.equal(3, result.ops.length);
console.log("Inserted 3 documents into the collection");
callback(result);
});
}
其中,文档对应mysql中的表,在上段代码中文档名为documents,
将上述方法添加进app.js
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
insertDocuments(db, function() {
client.close();
});
});
运行程序可查看返回结果
node app.js
const findDocuments = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Find some documents
collection.find({}).toArray(function(err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs)
callback(docs);
});
}
find()方法中可添加查询条件,上述代码中为空,所以为查询所有文档,在app.js中添加该方法
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected correctly to server");
const db = client.db(dbName);
insertDocuments(db, function() {
findDocuments(db, function() {
client.close();
});
});
});
此时,执行程序,可查看返回结果
如果要按照条件查询,方法应改为
const findDocuments = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Find some documents
collection.find({'a': 3}).toArray(function(err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs);
callback(docs);
});
}
该方法表示查询属性a值为3的所有数据
const updateDocument = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Update document where a is 2, set b equal to 1
collection.updateOne({ a : 2 }
, { $set: { b : 1 } }, function(err, result) {
assert.equal(err, null);
assert.equal(1, result.result.n);
console.log("Updated the document with the field a equal to 2");
callback(result);
});
}
const removeDocument = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Delete document where a is 3
collection.deleteOne({ a : 3 }, function(err, result) {
assert.equal(err, null);
assert.equal(1, result.result.n);
console.log("Removed the document with the field a equal to 3");
callback(result);
});
}
const indexCollection = function(db, callback) {
db.collection('documents').createIndex(
{ "a": 1 },
null,
function(err, results) {
console.log(results);
callback();
}
);
};
在原文中,如果设计到两个及两个以上的数据库操作,方法都通过嵌套的方式来解决异步的问题,如先插入数据再建立索引
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
insertDocuments(db, function() {
indexCollection(db, function() {
client.close();
});
});
});
当要嵌套的方法很多时,代码看起来会很复杂
建议通过async来调用异步方法
MongoClient.connect(url, async function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
await insertDocuments(db, function(data) {
console.log('hello');
});
await indexCollection(db, function(){
console.log('add index');
})
client.close();
});
这样写显然可读性更好,并且操作简单,async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。更详细的方法请参考阮一峰的 ECMAScript 6入门
const db = client.db(dbName);
const collection = db.collection('test');
// 批量操作
/*
{ insertOne: { document: { a: 1 } } }
{ updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
{ updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
{ deleteOne: { filter: {c:1} } }
{ deleteMany: { filter: {c:1} } }
{ replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
*/
let rand = Math.ceil(Math.random() * 10);
// 批量处理 在方法前用await做标记,运行时仍然会执行后边的操作,(先关闭连接)
await collection.bulkWrite([
{
insertOne: {
document: { a: rand, b: 2}
}
}, {
updateOne: {
filter: { a: 5}, // 如果没有符合的条件,会创建新的数据
update: { $set: { a: 2}},
upsert: true
}
}
], function(err, result) {
if (err) return console.log('err', err);
// console.log(result);
})
// 查询数量,
// 有时候会因为分片等原因 count()方法查询的数量不准确,可用聚合来查询
await collection.count({
'a': 1
}, {}, function(err, result) {
if (err) return console.log('err', err);
console.log(result);
})
// 删除数据
await collection.deleteOne({'a':1},{}, function(err, result){
if (err) return console.log('err', err);
console.log(result);// 返回值 result.result.n 为删除的数量 result.result.ok 1代表执行成功
})
await collection.deleteMany({'a':1},{}, function(err, result){
if (err) return console.log('err', err);
console.log(result);// 返回值 result.result.n 为删除的数量 result.result.ok 1代表执行成功
})
// 按条件查询某个字段不重复的数据
await collection.distinct('a', {}, {}, function(err, result) {
if (err) return console.log('err', err);
console.log('distinct', result);
})
// 查询
// projection设置的字段值为0 则不显示该字段,显示其他字段, 为其他数字,只显示该字段和_id
// find()方法与fandOne()不同: find()没有回调方法,需调用toArray()方法进行回调
await collection.find({},{'sort':[['a',-1]],'projection':{'b':0}}).toArray(function(err, result){
if (err) return console.log('err', err);
console.log('find', result);
});
await collection.findOne({},{'sort':[['a',-1]],'projection':{'b':0}}, function(err, result){
if (err) return console.log('err', err);
console.log('find', result);
});
await collection.findOneAndReplace({'a': 1},{'aa':11},{'sort':[['b',-1]]}, function(err, result){
if (err) return console.log('err', err);
console.log('findOneAndReplace', result);
});
// update和replace有什么区别??
await collection.findOneAndUpdate({'aa': 11}, {'aa':11}, {'sort':[['b',-1]]}, function(err, result){
if (err) return console.log('err', err);
console.log('findOneAndUpdate', result);
});
// sort在findAndModify()中变为了数组
await collection.findAndModify({'aa': 11}, [['b',-1]], {'bb':22}, function(err, result){
if (err) return console.log('err', err);
console.log('findAndModify', result);
});
await collection.findAndRemove({'bb': 22}, [['b',-1]], function(err, result){
if (err) return console.log('err', err);
console.log('findAndRemove', result);
});
// 插入
await collection.insertOne({'cc': 33}, function(err, result){
if (err) return console.log('err', err);
console.log('insertOne', result);
});
await collection.insertMany([{'cc': 33},{'dd': 44}], function(err, result){
if (err) return console.log('err', err);
console.log('insert', result);
});
// insert() 第一个参数可以是对象,也可以是数组 => 同时包含insertOne()和insertMany()两种功能,但被官方弃用了
await collection.insert([{'aa': 11}, {'cc': 33}], function(err, result){
if (err) return console.log('err', err);
console.log('insert', result);
});
// 更新
// MongoError: the update operation document must contain atomic operators. => 需要加 $set
// 如果更新的参数之前不存在,updateONe的结果是在这条数据中新增一个字段,而不是更新这个字段
// updateOne似乎没有filter,所以只能更新查询到的第一个?? 那么最好用findOneAndUpdate()
await collection.updateOne({'cc': 33}, {$set:{'dd': 44}}, function(err, result){
if (err) return console.log('err', err);
console.log('updateOne', result);
});
await collection.updateMany({'cc': 33}, {$set:{'dd': 4444}}, function(err, result){
if (err) return console.log('err', err);
console.log('updateMany', result);
});
// 聚合 db.newsHk.aggregate([{ $group: { _id: null, mycount: { $sum: 1 } } } ])
// $sum 后的参数代表获取到的数量乘以的倍数
await collection.aggregate([{ $group: { _id: null, mycount: { $sum: 1 } } } ]).toArray(function(err, result){
if (err) return console.log('err', err);
console.log(result);
})
// 查询a小于8 b大于2的数据,并且过滤b
// $lte 小于等于 $lt 小于 $gt 大于 $gte 大于等于,如果判断值为变量,需要*1,以防止数据类型不对。
await collection.find({'a': {$lt:8}, 'b':2},{'limit':2, 'projection':{'b': 0}}).toArray(function(err, result){
if (err) return console.log('err', err);
console.log(result);
})
// 在查询时引用变量,mongodb会认为变量名为属性名,attribute为变量名,解决方法
// attribute => [`${attribute}`]
collection.findOne({'source': source}, {'projection': {[`${attribute}`] : 1, '_id': 0}}, function(err, result){
if (err) return console.log('err', err);
console.log(result);
})
client.close();
aggressive的文档
node操作mongodb的官方API
未完,待续…