Mongodb 入门

第一章 前言

1.1 知识体系分析

  • 前端工程师:Web前端,也就是在Web应用中用户可以看得见碰得着的东西。包括Web页面的结构、Web的外观视觉表现以及Web层面的交互实现。

  • 后端工程师:与数据库进行交互以处理相应的业务逻辑,提供数据供前端显示。需要考虑的是如何实现功能、数据的存取、平台的稳定性与性能等。

1.2 mongodb概述

mongodb 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
mongodb 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

  • 关系型数据库(sql):数据以表格形式存储,通过表格的行列关系进行检索,每一行的内容,必是符合表结构的,就是说--列的个数,类型都一样.
  • 文档型数据库(no-sql not-only-sql):数据以文档类型进行存储,数据之间没有严格的映射关系.

mongodb是一种文档形数据库,数据以key/value形式存储,内部执行引擎为JS解释器, 把文档存储成bson结构,通过gridefs系统存储文件,在查询时,转换为js对象,并可以通过熟悉的js语法来操作.

第二章 Mongodb在windows下的安装

2.1 mongodb的安装

  • 下载最新stable版的mongodb www.mongodb.org;
  • 不需要编译,一路next安装

2.2 目录结构

  • bsondump: binary-json,二进制文件,选择性导出bson文件
  • mongo: 客户端
  • mongod: 服务端
  • mongodump: 整体导出数据库(二进制)
  • mongoexport:导出易识别的json文档
  • mongoimport:导入json文档
  • mongorestore:数据库整体导入
  • mongos: 路由器(分片)

2.3 启动mongod服务

./bin/mongod.exe --dbpath /path/to/database --logpath /path/to/log-file --port 27017

参数解释:

  • dbpath 数据存储目录
  • logpath 日志存储文件
  • port 运行端口(默认27017)

打开localhost:27017页面,可以看到以下信息:

It looks like you are trying to access MongoDB over HTTP on the native driver port.

证明服务器启动成功.

然后另外开启一个命令窗口,执行mongo.exe,进入mongodb客户端.

2.4 基本概念解释

MongoDB术语/概念 解释/说明
database 数据库
collection 数据库表/集合
document 数据记录行/文档
field 数据字段/域
index 索引
primary key 主键,MongoDB自动将_id字段设置为主键

第三章 Mongodb入门命令

3.1 基本查看命令

  • show dbs 查看当前的数据库
  • use databaseName 选库
  • show tables/collections 查看当前库下的collection

3.2 库和collection的操作

  • db
    查看当前所处的数据库

  • 在mongodb中,库是隐式创建,
    你可以use 一个不存在的库, 然后在该库下创建collection,即可创建库

  • db.dropDatabase();
    删除database

  • db.createCollection(‘collectionName’)
    创建collection

  • collection也是允许隐式创建的
    db.collectionName.insert(document);
    在集合(表)中插入具体数据的时候会自动创建

  • db.collectionName.drop() ,
    删除collection

第四章 Mongodb基本增删改查操作

4.1 增加数据

mongodb存储的是文档,文档是json格式的对象,我们向数据库存储数据的时候可以使用insert方法,数据格式要以js对象格式进行存储:
语法:db.collectionName.insert(document);

我们可以以多种方法对文档进行存储:

4.1.2 增加单篇文档

db.collectionName.insert({title:"nice day"});

4.1.3 增加单个文档,并且指定_id

_id是我们在插入数据的时候,mongodb自动给文档添加的一个属性,如果我们不需要系统分配_id,可以在添加数据的时候手动设置,覆盖原有_id,虽然_id的类型可以自由指定,但是在同一个集合当中必须唯一,如果插入重复的值,系统会抛出异常.

这个_id的名称是固定的,它可以是Mongodb支持的任何数据类型,默认是ObjectId,在关系型数据库中,主键通常是数值型的,并且可以设置自增,反观Mongodb的主键,原生不支持自增主键.

db.collectionName.insert({_id:8,age:78,name:"lisi"});
> db.stu.insert({_id:3,age:17})
WriteResult({ "nInserted" : 1 })
> db.stu.insert({_id:3,age:14})
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "E11000 duplicate key error collection: web.students index: _id_ dup key: { : 3.0 }"
        }
})

4.1.4 增加多个文档

db.collectionName.insert(
    [
        {time:'friday',study:'mongodb'},
        {_id:9,gender:'male',name:'QQ'}
    ]
 )

可以以数组的方式,一次性向集合插入多个数据;

同时应该注意的是,由于mongodb采用的是JavaScript Shell,所以我们可以根据js特性,将文档作为值赋给变量然后进行操作:

j = {name : "mongo"};
t = {x:3};
db.stu.insert([j,t]);

4.1.5 save和insert的区别

save和insert都可以进行数据的插入和增加,但是也有一些异同:

对于已存在数据{_id:1, "name":"n1"},再次进行插入操作时,insert({_id : 1, "name" :"n2"})会报主键重复的错误提示save({ _id:1, " name ":"n2"})会把n1修改为n2。

相同点:
若新增的数据中没有主键时,会增加一条记录。

4.2 查询操作

4.2.1 find()

无条件的普通查询方式很简单,可以直接使用
db.collectionName.find();一次可以查出指定集合中的所有数据

for(var i = 1;1<10;i++) db.stu.save({x:4,y:3});
db.stu.find();

如果出现显示不全的现象,可以使用"it"命令,继续显示下面的数据.

当然,我们还可以按照条件进行查询操作

语法: db.collection.find(查询表达式,查询的列);

例1: db.stu.find({},{gendre:1})
查询所有文档,的gender属性 (_id属性默认总是查出来)

例2: db.stu.find({},{gender:1, _id:0})
查询所有文档的gender属性,且不查询_id属性

此处的0表示的是false,不查询

例3: db.stu.find({gender:’male’},{name:1,_id:0});
查询所有gender属性值为male的文档中的name属性

4.2.2 findOne()

findOne()和find()函数一样,只是findOne()返回的是查询结果中的第一条数据,或者返回null.

db.stu.findOne(查询表达式,查询的列)

4.3 删除操作

语法: db.collectionName.remove(查询表达式, 选项);

选项是指 {justOne:true/false},是否只删一行, 默认为false

注意

  • 1: 查询表达式依然是个json对象
  • 2: 查询表达式匹配的行,将被删掉.
  • 3: 如果查询表达式为空对象{},collections中的所有文档将被删掉.

例1: db.stu.remove({sn:'001'});

删除stu表中sn属性值为'001'的文档

例2: db.stu.remove({gender:'m'},true);

删除stu表中gender属性为m的文档,只删除1行.

4.4 修改操作

语法: db.collection.update(查询表达式,新值,选项);

* 改哪几行? --- 查询表达式
* 改成什么样? -- 新值 或 赋值表达式
* 操作选项 ----- 可选参数
        upsert:如果要更新的那条记录没有找到,是否插入一条新纪录,默认为false
        multi :是否更新满足条件的多条的记录,默认为false 

multi :是否更新满足条件的多条的记录,false:只更新第一条,true:更新多条,默认为false

例:db.news.update({name:'QQ'},{name:'MSN'});

是指选中news表中,name值为QQ的文档,并把其文档值改为{name:"MSN"},

结果: 文档中的其他列也不见了,改后只有_id和name列了.即是新文档直接覆盖了旧文档,而不是修改.

4.4.1 修改操作中的关键字

如果是想修改文档的某列,可以用$set关键字

db.collectionName.update(query,{$set:{name:’QQ’}})

修改时的赋值表达式

  • $set 修改某列的值
  • $unset 删除某个列
  • $inc 增长某个列
  • $rename 重新命名某列
  • $setOnInsert 当upsert为true时,并且发生了insert操作时,可以补充的字段.
$inc实例

按照指定的步长增长某个列;

> db.stu.insert({"uid":"201203","type":"1",size:10})
> db.stu.find()
{ "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1",
"size" : 10 }
> db.stu.update({"uid" : "201203"},{"$inc":{"size" : 2}})
> db.stu.find()
{ "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1",
"size" : 12 }
$unset实例
>db.stu.find({_id:3})
{"_id" : 3 , "age" : 18}
> db.stu.update({_id:3},{$unset:{age:'sss'}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.stu.update({_id:3},{$unset:{age:'sss'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.stu.find({_id:3})
{ "_id" : 3 }
$rename实例
->db.stu.insert({name:'lisi',age:12,sex:'male',height:123,area:'haidian'});
->db.stu.update({name:'lisi'},{$set:{area:'chaoyang'},$unset:{height:1},$inc:{age:1},$rename:{sex:'gender'}});

4.4.2 Option选项的作用:

{upsert:true/false,multi:true/false}

  • upsert:是指没有匹配的行,则直接插入该行

例:db.stu.update({name:'wuyong'},{$set:{name:'junshiwuyong'}},{upsert:true});
如果有name='wuyong'的文档,将被修改,如果没有,将添加此新文档

例:db.news.update({_id:99},{x:123,y:234},{upsert:true});
没有_id=99的文档被修改,因此直接插入该文档

  • multi: 是指修改多行(即使查询表达式命中多行,默认也只改1行,如果想改多行,可以用此选项)

例:db.news.update({age:21},{$set:{age:22}},{multi:true});
则把news中所有age=21的文档,都修改

4.5 查询表达式

我们无论在修改删除还是查询的过程中,都需要传入查询表达式对目标数据进行查询,表达式有很多种

1: 最简单的查询表达式
{filed:value} ,是指查询field列的值为value的文档

2: $ne:!=
{field:{$ne:value}}
db.stu.find({age:{$ne:16}})
作用--查age列的值 不等于16的文档

3:$gt:大于
  $lt:小于
  $gte:大于或等于
  $lte:小于或等于

4: $in:[]
查询某列的值在范围内的文档
db.goods.find({cat_id:{$in:[2,8]}}

5: $nin:not in
查询某列不在范围内的文档
$nin:[2,3,5]

6: $exists 
语法: {field:{$exists:1}}
作用: 查询出含有field字段的文档

7:用正则表达式查询 以”诺基亚”开头的商品
例:db.goods.find({goods_name:/诺基亚.*/},{goods_name:1});

第五章 游标操作

通俗的说,游标不是查询结果,而是查询的返回资源,或者接口,通过这个接口,你可以逐条对数据进行读取;

声明游标:

var cursor = db.collectioName.find(query,projection);
cursor.hasNext() //判断游标是否已经取到尽头
cursor.next() //取出游标的下1个单元

用while来循环游标

> var mycursor = db.bar.find({_id:{$lte:5}})
> while(mycursor.hasNext()) {
    printjson(mycursor.next());
}

游标还有一个迭代函数,允许我们自定义回调函数来逐个处理每个单元.

cursor.forEach(回调函数);

> var gettitle = function(obj) {print(obj.goods_name)}
> var cursor = db.goods.find();
> cursor.forEach(gettitle);

游标在分页中的应用

比如查到10000行,跳过100页,取10行,一般地,我们假设每页N行, 当前是page页,就需要跳过前 (page-1)*N 行, 再取N行.

在mongo中,分页是用skip(), limit()函数来实现的

//查询结果中,跳过前9995行
var mycursor = db.bar.find().skip(9995);

//查询第901页,每页10条
则是 var mytcursor = db.bar.find().skip(9000).limit(10);

第六章 MongoDB在Node环境中使用

我们如果想要将mongodb用于实际的开发中于nodejs作为交互,需要下载node下的mongodb服务器模块.

在项目根目录下运行

npm install mongodb --save 

安装完毕后启动mongodb的服务端mongod.exe,我们就可以通过js代码的形式链接mongodb数据库了

6.1 快速开始

官方API地址:http://mongodb.github.io/node-mongodb-native/2.2/quick-start/quick-start/

var myClient = require('mongodb').MongoClient;
var server = 'mongodb://localhost:27017/web';//连接web集合
myClient.connect(server,function(err,db){//连接数据库
    if(!err){
        console.log(db);
        db.close();       //关闭数据库
    }
})

6.2 增加数据

插入数据有insertOne和insertMany两种方法

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
  db.collection('inserts').insertOne({a:1}, function(err, res) {
    //insertOne插入一条数据
      console.log(res.insertedCount);
    //返回值对象里的insertedCount表示插入数量
    });
    db.collection('inserts').insertMany([{a:2},{a:3}], function(err, res) {
    //insertOne插入多条数据
      console.log(res.insertedCount);
      db.close();
    });
});

6.3 查询数据

查询所有的文档数据

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').find({}).toArray(function(err,docs){
            if(!err){
                console.log(docs);
            }
            db.close();
        });
});

当然,我们可以使用条件查询数据

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').find({a:{$ne:2}}).toArray(function(err, docs) {
        if (!err) {
            console.log(docs);
        }
        db.close();
    });
});

查询数据的过程中,我们同样可以使用skip(),limit()等方法

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').find({a:{$ne:2}}).skip(4).limit(2).toArray(function(err, docs) {
        if (!err) {
            console.log(docs);
        }
        db.close();
    });
});

查询过程中的连续操作

在查询的过程中,给我们提供了三个连续操作的API findOneAndUpdate, findOneAndDelete, findOneAndReplace,使用起来也非常方便

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').findOneAndUpdate({a:1},{$set:{b:3}},function(err,res){
      console.log(res);
    });
    db.close();
});
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').findOneAndDelete({b:3},function(err,res){
      console.log(res);
    });
    db.close();
});

6.4 删除操作

我们可以使用deleteOne和deleteMany方法删除collection中的数据

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').deleteOne({a:1},function(err,res){
      console.log(res.deletedCount);
    });
    db.close();
});
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').deleteMany({a:2},function(err,res){
      console.log(res.deletedCount);
    });
    db.close();
});

6.5 修改操作

同样,update操作也可以使用updateOne和updateMany两种方法,在修改的同时也可以使用查询表达式.

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').updateOne({a:1},{$set:{b:2}},function(err,res){
      console.log(res.modifiedCount);
    });
    db.close();
});

{upsert: true}帮助我们在修改不存在的数据时插入一条新数据`

注意

如果按照"_id"进行查询或者修改的话,直接填入_id的值是不能获取结果的,因为mongodb的_id默认值是ObjectId类型的

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').find({_id:"58b04104ae7db136d00ebb66"}).toArray(function(err, docs) {
        if (!err) {
            console.log(docs);
        }
        db.close();
    });
});

会发现方法正确但是没有返回值;如果我们想要按照主键查找,需要引入Object模块:

var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectId;
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
    db.collection('inserts').find({_id:ObjectId("58b04104ae7db136d00ebb66")}).toArray(function(err, docs) {
        if (!err) {
            console.log(docs);
        }
        db.close();
    });
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 安装 MongoDB Windowns、Ubuntu17.10 下安装 MongoDB教程在此 MongoDB 帮...
    Kangvcar阅读 2,087评论 0 13
  • MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方...
    入戏半分笑阅读 365评论 0 2
  • MongoDB与关系型数据库对比 MongoDB属于文档型的非关系型数据库,其他像Redis就属于键值对型的非关系...
    少见多怪阅读 1,741评论 0 4
  • 1.express node Web应用框架,提供了很多Web应用和HTTP工具 使用express可以快速搭建一...
    寒梁沐月阅读 432评论 2 6
  • 1.express node Web应用框架,提供了很多Web应用和HTTP工具 使用express可以快速搭建一...
    昵称不能太随便阅读 1,320评论 0 2