mongodb入门指南


在ubuntu下的部署

参考 http://html5beta.com/page/mongodb-deploy-replset.html

启动

# 以特定配置文件 ~/confs/mongod.conf 启动mongod
mongod --config ~/confs/mongod.conf

推荐以 pm2 启动mongod服务

pm2 start start-mongod.sh

# start-mongod.sh内容如下

#!/bin/bash
mongod --config ~/confs/mongod.conf

关于 pm2 安装,参考

https://github.com/zxdong262/long/wiki/install-nodejs-on-centos

https://github.com/zxdong262/long/wiki/init-nodejs-on-ubuntu-14.04-tip

mongodb命令

# 备份test数据库到当前文件夹
mongodump --db test

# 把mn文件夹下的数据备份恢复到test数据库
mongorestore --db test ./mn

# 对test数据库批量执行bat.js的命令,可以用于数据库初始化等
mongo localhost:27017/test bat.js

进入数据库cli

mongo
#默认当前数据库位test

数据库命令

// 列举当前数据库列表
show dbs

// 切换到test2数据库
use test2

// 帮助
db.help()

//删除数据库
db.dropDatabase()

collection(数据列,相当于表)命令

查询

// *数据列无需预先定义和建立

//// 插入数据
db.user.insert({ name: 'zxd', age: 20 })
db.user.insert({ name: 'zxdx', _id: 'fff', age: 20 })

//// 插入多个数据
db.user.insert([
  { name: 'zxd1', age: 20 }
  ,{ name: 'zxd2', age: 20 }
])

//// 查找单个数据 findOne
db.user.findOne({ name: 'zxd' })

// 结果为{ "_id" : ObjectId("554acf6ae37cda7a26c7e14f"), "name" : "zxd", "age": 20 }
// 如果没有插入_id,mongo自动插入ObjectId

db.user.findOne({ name: 'zxdx' })
// 结果为{ "_id" : "fff", "name" : "zxdx", "age": 20 }

// 指定输出数据列 true/false, 1/0都可以
db.user.findOne({ name: 'zxdx' }, { name:  true, _id: 0 })

// 除了_id以外不可混用 
// 错误: db.user.findOne({ name: 'zxdx' }, { name:  1, age: 0 })
// 正确: db.user.findOne({ name: 'zxdx' }, { name:  1, age: 1 })
// 正确: db.user.findOne({ name: 'zxdx' }, { name:  0, age: 0 })
// 正确: db.user.findOne({ name: 'zxdx' }, { name:  1, _id: 0 })

//查找数组
db.user.insert([
  { name: 'zxd4', age: 20, lang: ['c', 'js'] }
  ,{ name: 'zxd5', age: 20, lang: ['c++', 'html5'] }
])

db.user.findOne({ lang: 'c++' })
/* 结果为
  {
    "_id" : ObjectId("554ad4a7e37cda7a26c7e154"),
    "name" : "zxd5",
    "age" : 20,
    "lang" : [
      "c++",
      "html5"
    ]
  }
*/

//查找子文档
db.user.insert([
  { name: { first: 'z', last: 'xd7'}, age: 50, lang: ['c', 'js'] }
  ,{ name: { first: 'z', last: 'xd8'}, age: 20, lang: ['c++', 'html5'] }
  ,{ name: { first: 'z', last: 'xd9'}, age: 100, lang: ['c++', 'html5'] }
])

db.user.findOne({ 'name.last': 'xd8' })
/* 结果为
  {
    "_id" : ObjectId("554ad59fe37cda7a26c7e156"),
    "name" : {
      "first" : "z",
      "last" : "xd8"
    },
    "age" : 20,
    "lang" : [
      "c++",
      "html5"
    ]
  }

*/

索引和查询细节

//查询细节 find有,findOne没有
db.user.find({ 'name.last': 'xd8' }).explain()

//结果如下
//扫描了15次
//找到2个结果
{
  "cursor" : "BasicCursor",
  "isMultiKey" : false,
  "n" : 2,
  "nscannedObjects" : 15,
  "nscanned" : 15,
  "nscannedObjectsAllPlans" : 15,
  "nscannedAllPlans" : 15,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 3,
  "server" : "ubuntu:27017",
  "filterSet" : false
}

//创建索引 1降序, -1升序
db.user.createIndex({ 'name.last': 1 })

//再次查询结果如下
{
  "cursor" : "BtreeCursor name.last_1",
  "isMultiKey" : false,
  "n" : 2,
  "nscannedObjects" : 2,
  "nscanned" : 2,
  "nscannedObjectsAllPlans" : 2,
  "nscannedAllPlans" : 2,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 12,
  "indexBounds" : {
    "name.last" : [
      [
        "xd8",
        "xd8"
      ]
    ]
  },
  "server" : "ubuntu:27017",
  "filterSet" : false
}

#列举索引
db.system.indexes.find()

操作符

//操作符 $gt $lt $lte $gte
db.user.findOne({ age: { $gt: 20 } })

//使用多个操作符
db.user.findOne({ age: { $gt: 20, $lt: 100 } })

//操作符 $in $nin
db.user.findOne({ age: { $in: [20, 50] } })
db.user.findOne({ age: { $nin: [20, 50] } })

//操作符 $all 相当于 ===
db.user.findOne({ lang: { $all: ['c', 'js'] } })

//操作符 $ne
db.user.find({ lang: { $ne: 'c' } })

//操作符 $nor 返回全部fasle的结果
db.user.find({ $nor:[ { name: 'zxd' }, { age: 50 } ] })

//操作符 $and 返回全部true的结果
db.user.find({ $and:[ { name: 'zxd' }, { age: { $gte: 20 } } ] })

//操作符 $exists 返回键值非undefined
db.user.find({ lang: { $exists: true } })

//操作符 $mod Math.mod(age/25) === 0
db.user.find({ age: { $mod: [25, 0] } })

//结果为
/*
  { "_id" : ObjectId("554ad9a2e37cda7a26c7e157"), "name" : { "first" : "z", "last" : "xd7" }, "age" : 50, "lang" : [ "c", "js" ] }
  { "_id" : ObjectId("554ad9a2e37cda7a26c7e159"), "name" : { "first" : "z", "last" : "xd9" }, "age" : 100, "lang" : [ "c++", "html5" ] }
*/

//操作符 $not 
db.user.find({ age: { $not:{$mod: [5, 0]} } })

//$elemMatch 查找数组子文档
db.user.insert([
  { name: 'a', age: 50, children: [
    {
      name: 'a1'
      ,age: 1
    }
    ,{
      name: 'a2'
      ,age: 2
    }
  ]}
  ,{ name: 'b', age: 40, children: [
    {
      name: 'b1'
      ,age: 4
    }
    ,{
      name: 'b2'
      ,age: 2
    }
  ]}
  ,{ name: 'c', age: 30, children: [
    {
      name: 'c1'
      ,age: 3
    }
    ,{
      name: 'c2'
      ,age: 2
    }
  ]}
])

db.user.find({ children: { $elemMatch:{ age: 1 } } })

/*结果为
  { "_id" : ObjectId("554adca4e37cda7a26c7e15a"), "name" : "a", "age" : 50, "children" : [ { "name" : "a1", "age" : 1 }, { "name" : "a2", "age" : 2 } ] }
*/

// 操作符 $where 出于性能考虑,请在其他方式可行的时候不要使用where
db.user.find({ $where: 'this.name.first === "z"'})

//或者省略$where
db.user.find('this.name.first === "z"')

//还可以用function
var f = function () { return this.name.first === 'z'}
db.user.find(f)
db.user.find({ $where: f })

//操作符 $regex 正则
db.user.find({ name:  /d5$/ })

排序

//排序 descend降序 -1,ascend升序 1
db.user.find({ name:  /z/ }).sort({ name: 1, age: -1 })

分页(limit, skip)

//有限返回数据limit和跳过数据skip, 以分页为例
var page = 1
var pageSize = 3
db.user.find({}).skip(pageSize * (page - 1)).limit(pageSize)

findOne 和find返回数据的不同

//find 返回的是cursor指针
//findOne返回Object
//使用toArray把cursor转换为数组
db.user.find('this.name.first === "z"').toArray()

删除文档remove

#所有查询都通用
db.user.remove('this.name.first === "z"')

//删除整个collection
db.user.drop()

修改文档update

// 完全替换
db.user.update({ 'name': 'zxd' }, { name: 'webber' })

// 修改特定属性 $set, 如果没有对应属性,则插入该属性
db.user.update({ 'name': 'zxd' }, { $set: { name: 'webber', age: 900, game: 'skyrim' } })

// 删除特定属性 $unset
db.user.update({ 'name': 'zxd' }, { $unset: { age: 900, game: 'skyrim' } })

// 修改多个文档
db.user.update({ 'name': 'zxd' }, { name: 'webber' }, { multi: true })

// 操作符 $inc 自增
db.user.update({ 'name': 'zxd' }, { $inc: { age: 2 } })

// db.col.save(doc)
// 如果没有doc._id 等同于 db.col.insert(doc)
// 如果有doc._id 等同于 db.col.update({ _id: doc._id }, { $set: doc })

// findAndModify 查找并修改文档
// 如果new = true, 返回修改后的文档,
// 如果remove = true, 则删除文档
db.user.findAndModify({
  query: { name: 'zxd' }
  ,update: { $inc: { age: 1 } }
  ,new: true 
  ,sort: { title: 1 }
  ,fields: { title: 1, _id: 0}
  //,remove: true //this will remove it
})

//一个常见的应用是数字自增id
db.meta.findAndModify({
  query: { name: 'userIdCount' }
  ,update: { $inc: { userIdCount: 1 } }
  ,new: true
})

update数组操作符

// $push 加入元素
db.user.update({ 'name': 'jane' }, { $push: { lang: 'java' } })

// $pushAll 加入多个元素
db.user.update({ 'name': 'jane' }, { $pushAll: { lang: ['java', 'bash'] } })

// $addToSet : 加入非重复元素
db.user.update({ 'name': 'jane' }, { $addToSet: { lang: 'java' } } )

// $addToSet : 加入多个非重复元素
db.user.update({ 'name': 'jane' }, { $addToSet: { lang: { $each: ['one', 'two']} } } )


// $pull 删除元素, 重复的元素都会被删除
db.user.update({ 'name': 'jane' }, { $pull: { lang: 'c++' } }, )


// $pullAll 删除多个元素, 重复的元素都会被删除
db.user.update({ 'name': 'jane' }, { $pullAll: { tags: ['new tag', 'bgy'] } }, )

// $pop 出栈 从队尾删除 1, 从队首删除 -1
db.user.update({ 'name': 'jane' }, { $pop: { lang: 1 } })

# 属性改名$rename
db.user.update({ 'logins.times' : true }, { $rename: { 'times' : 'time' } })

//子数组修改
db.user.find({ 'children.age' : 1 })
db.user.update({ 'children.age' : 1 }, { $inc: { 'children.$.age' : 1 } })

distinct 获得去重数据列数组

db.user.distinct('age')

//结果为[ 20, 50, 100, 40, 30 ]

count计数

db.user.count({name: { $regex: /z/ }})
db.user.find({name: { $regex: /z/ }}).count()

mapReduce 数据统计...

db.collection.mapReduce(
   map,
   reduce,
   {
     out: collection,
     query: document,
     sort: document,
     limit: number,
     finalize: function,
     scope: document,
     jsMode: boolean,
     verbose: boolean
   }
 )
db.user.insert(
  [
    { author : 'cj', study_hour: 3 }
    ,{ author : 'cj', study_hour: 5 }
    ,{ author : 'dt', study_hour: 1 }
    ,{ author : 'dt', study_hour: 34 }
    ,{ author : 'dtx', study_hour: 44 }
  ]
)


var map = function() {

  emit(this.author, { count: this.study_hour, reduced: false })
}

//依据key值有多条数据的才会进入reduce function, author ='dtx'不会被reduce function 处理
var reduce = function(id, values) {
  var reduced = { 
    reduced: true 
    ,count: 0
  }
  values.forEach(function(val) {
    reduced.count += val.count
  })
  return reduced
}

//在finalize里,reduced是每个最终结果,还可以做最后处理
var finalize  = function(key, reduced) {
  var reducedx = reduced
  reducedx.x = 'xx'
  return reducedx
}

//out:表示数据输出的collection和方式
db.user.mapReduce(map, reduce, {
  query : { author: { $exists: true } },
  sort : { author : 1 },
  out : { replace: 'user_reduced' },
  finalize: finalize
})

//查询结果
db.user_reduced.find()

{ "_id" : "cj", "value" : { "reduced" : true, "count" : 8, "x" : "xx" } }
{ "_id" : "dt", "value" : { "reduced" : true, "count" : 35, "x" : "xx" } }
{ "_id" : "dtx", "value" : { "count" : 44, "reduced" : false, "x" : "xx" } }

db.collection.group

db.collection.group({ key, reduce, initial [, keyf] [, cond] [, finalize] })
//details:todo...


更多...

参阅 http://docs.mongodb.org/manual/reference/

或者参阅 mongodb cheatsheet

nodejs + mongodb?

[原生驱动] https://github.com/mongodb/node-mongodb-native

[原生驱动文档] http://mongodb.github.io/node-mongodb-native/2.0/api-docs/

[Schema!] https://github.com/Automattic/mongoose

[Promise!] https://github.com/zxdong262/promise-mongo