mongodb与node

本文主要讲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
  • 初始化项目结构,并安装mongodb的依赖包
npm init
npm install mongodb --save
  • 创建数据库目录并开启mongodb
mongod --dbpath=/data
  • 创建app.js文件,并连接数据库myproject
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

未完,待续…

你可能感兴趣的:(node)