Node学习笔记三:Hello MongoDB
1.安装
1.1 使用brew安装
Mac 上面比较简便的安装方法是使用brew
由于网络环境的限制,安装的时候可以设置代理
http_proxy=https://ip:port brew install mongodb
如果报错,先升级 brew
http_proxy=https://ip:port brew update
如果还是没有用,可以通过设置好代理的浏览器中输入brew请求的下载地址,进行下载。下载完毕后,将mongodb-3.0.6.yosemite.bottle.tar.gz
移动到Library/Caches/Homebrew
中(此目录存放着brew下载好包文件)再重新执行 brew install mongodb
测试是否安装成功,执行命令mongod
mongod
2015-09-14T09:00:32.799+0800 I STORAGE [initandlisten] exception in initAndListen: 29 Data directory /data/db not found., terminating
2015-09-14T09:00:32.800+0800 I CONTROL [initandlisten] dbexit: rc: 100
从提示可以看出,需要创建/data/db
目录,现在我们设置一下,执行以下两行命令:
sudo mkdir -p /data/db
sudo chown `id -u` /data/db
-p
是如果当前的父级目录不存在则创建它;
id -u
是将所有者指定到当前用户;用whoami
也起相同的效果;
sudo chown `whoami` /data/db
最后再执行一下mongod
就可以看到效果了;
mongod
参考资料:https://docs.mongodb.org/manual/tutorial/install-mongodb-on-os-x/
1.2 安装可视化工具mongohub
在 https://github.com/jeromelebel/MongoHub-Mac 下载MongoHub.zip文件,解压后拖入到应用程序中即可使用。使用起来也非常方便,摸一摸就会了。
2.使用MongoDB
2.1 使用mongodb 模块
安装mongodb模块
npm install mongodb
打开app.js文件,添加以下代码;
//引入模块
var mongodb = require('mongodb');
//创建一个连接实例,连接到MongoDB服务器
//主机的地址为localhost、端口号未27017。
//auto_reconnect:true,表示在链接中断后能够自动重新连接
var dbServer =new mongodb.Server('localhost', 27017,{auto_reconnect:true});
//创建一个数据库名为mydb
//第二个参数是上面创建的连接实例
//{w:1}是配置
var db = new mongodb.Db('mydb',dbServer,{w:1});
{w:1}是写入相关设置,表明这个是主mongod实例,只要你的 服务器上不超过一个MongoDB实例,就可以这样写。更多请参考:http://docs.mongodb.org/master/core/write-concern/
2. 2添加数据
首先我们要解释一下概念:Mongodb的结构中的“数据库”、“集合”、“文档”分别对应关系型数据库的:“数据库”、“表”、“行”的概念。
db.open(function(err,conn){
});
db.open()用于打开数据库,内部参数是一个异步回调函数
db.open(function(err,conn){
//创建一个名为myCollection的集合
db.collection('myCollection',function(err, collection){
var count = 0;
for (var i=0;i<5;i++){
//插入一个文档到集合
collection.insert({
num:i
},function(err,result){
//输出结果
console.log(result);
//添加计数
count++;
//如果计数器足够大,则关闭链接
if(count>4){
db.close();
}
});
}
});
});
collection.insert({},function(err,result){})
第一个参数是要插入的内容,第二个参数是插入成功时的回调函数;由于是插入数据不是顺序执行的,也就是说i=1可能会最后一个插入完成,整个插入顺序可能是3、4、2、1,如果通过if(i>4){}
来判断何时执行断开,可能会导致提前断开。因此需要添加一个外部计数器,每次插入成功后count加一,当count大于4的时候断开连接。
2.3 读取数据
2.3.1 读取所有数据
修改刚才的db.open()中的代码,使用collection.find()读取数据:
db.open(function(err,conn){
//选择集合
db.collection('myCollection',function(err, collection){
// 选择集合中所有的文档
collection.find().toArray(function(err,result){
//输出数据
console.log(result);
//关闭链接
db.close();
});
});
});
输出数据,如下:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 0 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 1 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 2 },
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 } ]
我们可以看出,虽然插入数据时结束的时间是无序的,但是插入时候的MongoDB的ID是有序的。
2.3.2 读取特定数据:
当collection.find()
没有特定参数时,为选择所有;如果需要选择查询特定内容时可以添加参数,例如我们要查询num为2的所有数据可以设置find()为find({num:2})
,mongodb会返回所有满足条件的数据,由于我们只有一条满足需求的数据,因此返回的集合中只有一条数据:
[ { _id: 55f65ff1ae0f94286cdabf19, num: 2 } ]
明明是一条数据,能不能不以集合的方式返回呢?
我们可以使用findOne()方法
collection.findOne({num:2},{},function(err,result){
console.log(result);
db.close({});
});
返回结果
{ _id: 55f65ff1ae0f94286cdabf19, num: 2 }
范围条件查询
如果我们要查询所有num>2的数据,我们可以将find()参数设置为{num:{$gt:2}}
$gt
操作符是great than 的缩写,运行后MongoDB返回两条数据:
[ { _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 } ]
如果我们要查询num<2的数据,我们可以使用$lt
lt 是little than 的缩写;设置find({num:{$lt:2}})
,返回结果:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 0 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 1 } ]
$gt
和$lt
可以组合使用,如果是num介于1和4之间,使用find({num:{$lt:4,$gt:1}})
可以返回结果:
[ { _id: 55f65ff1ae0f94286cdabf19, num: 2 },
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 } ]
更多操作符请参看:http://docs.mongodb.org/manual/reference/operator/
2.3.3 限制显示条数和配需
find()的一个参数是一个json对象,主要用于查询条件;第二个参数也是一个json对象,用于显示限制及排序:limit属性可以限制返回的条数,设置find({},{limit:2})
(第一个参数为{}表示查询所有),查看返回结果:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 0 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 1 } ]
排序:按照num进行降序排列:
find({},{limt:2,sort:[['num','desc']]}) (注意 是两层的[],因为你还能更具需要做不同优先级的排序),返回结果:
[ { _id: 55f65ff1ae0f94286cdabf1b, num: 4 },
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 } ]
2.4 更新数据:
2.4.1 更新单条数据
collection.update()
方法可以用来更新数据,修改db.open()
为以下代码:
db.open(function(err,conn){
//选择集合`myCollection`
db.collection('myCollection',function(err, collection){
// 更新集合中所有的文档
collection.update({num:2}, {num:10}, {safe: true},function(err){
if(err){
console.log(err);
}else{
console.log('Successfully update');
}
//查看集合中的内容
collection.find().toArray(function(err,result){
console.log(result);
db.close({});
});
});
});
});
返回结果:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 0 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 1 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 } ]
从上面的例子可以看出update()接受四个参数:
- 更新条件: { num:2 }表示更新num为2的记录,这里也可以使用find()中的高级操作符,例如
{num:{$lt:3}}
更新num小于3的记录:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 1 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10},
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 } ]
但是奇怪的事情发生了,num:1 不是也小于3吗,为何不更新?因为update() 一次只能更新一条,所以会先去更新num:0,如果你现在用Ctrl+C
停止服务后再执行npm start
返回的结果才为你预想的那样:
[ { _id: 55f65ff1ae0f94286cdabf17, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10},
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 } ]
- 要做的修改:本例中将满足条件的记录改成num:10;
- 更新选项:{safe: true}表示设置安全模式,这个应该一直使用;{mult: true}允许更新更多文档也是很常用的选项;
- 回调函数:操作成功或者失败后执行的函数,在这里我们除了在终端输出错误信息外,还使用collection.find()查看操作后的变化;
2.4.2 更新或者插入
在更新选项对象中设置{upsert:true},upsert 既是 update + insert ,如果查询的该条记录存在那么就是update,如果不存在就insert一条符合条件的数据。我们来试一试,修改上面的代码:
//如果有的话将num:8修改为num:7 ;如果没有的话,就插入一条num:7
collection.update({num:8}, {num:7}, {safe: true,upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log('Successfully update');
}
collection.find().toArray(function(err,result){
console.log(result);
db.close({});
});
});
发现返回的结果中多了一条num:7的数据;
[ { _id: 55f65ff1ae0f94286cdabf17, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf1a, num: 3 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 },
{ _id: 55f6acd1cbd052390a8e6368, num: 7 } ]
2.4.3 为指定文档添加字段和值
之前,都是在相应的文档中做原有字段的值的修改,如果需要添加新的字段怎么办?
可以用$set,代码如下:
collection.update({num:3}, {$set:{desc:'favorite number'}}, {safe: true,upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log('Successfully update');
}
collection.find().toArray(function(err,result){
console.log(result);
db.close({});
});
});
返回结果
[ { _id: 55f65ff1ae0f94286cdabf17, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf1b, num: 4 },
{ _id: 55f6acd1cbd052390a8e6368, num: 7 },
{ _id: 55f65ff1ae0f94286cdabf1a,
num: 3,
desc: 'favorite number' } ]
可以看出,我们update() 的第二个参数中使用了{$set:{desc:'favorite number'}
为num: 3 这条数据添加了desc
字段,并且值为:favorite number
:
2.4.4 查找并修改
2.5 删除数据
2.5.1 移除文档(行)
remove()可以移除整行的数据,修改之前的代码:
db.collection('myCollection',function(err, collection){
// 删除集合中num=4的文档
collection.remove({num: 4},function(err){
if(err){
console.log(err);
}else{
console.log("Successfully removed");
}
collection.find().toArray(function(err,result){
console.log(result);
db.close({});
});
});
});
返回结果,可以看出 num: 4的文档被成功删除:
Successfully removed
[ { _id: 55f65ff1ae0f94286cdabf17, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf18, num: 10 },
{ _id: 55f65ff1ae0f94286cdabf19, num: 10 },
{ _id: 55f6acd1cbd052390a8e6368, num: 7 },
{ _id: 55f65ff1ae0f94286cdabf1a,
num: 3,
desc: 'favorite number' } ]
如果将删除条件{num: 4}改成{num:10}的会产生怎么样的效果呢?
我们看返回的结果:
Successfully removed
[ { _id: 55f6acd1cbd052390a8e6368, num: 7 },
{ _id: 55f65ff1ae0f94286cdabf1a,
num: 3,
desc: 'favorite number' } ]
所有num:10的文档统统被删除了。因此,我们应当特别注意:
remove()是一次性针对所有满足条件的数据做操作
2.5.2 删除数据集合(表)
使用dropCollection()可以删除指定的集合;
db.open(function(err,conn){
db.dropCollection('myCollection',function(err, result){
if(err){
console.log(err);
}else{
console.log(result);
}
db.close();
});
});
返回
true
一定要慎重!