MongoDB 學習筆記

感謝 Karl Seguin 編寫的 The Little MongoDB Book 這本 MongoDB 入門書。javascript

本文內容主要來自「The Little MongoDB Book」的學習,學習筆記基於我的理解對原書部份內容進行調整。html

若是你是 MongoDB 數據庫初學者,建議從學習「The Little MongoDB Book」 開始。java

若是須要練習 MongoDB 相關命令行工具可直接閱讀本學習筆記。git

筆者測試 MongoDB 數據庫版本較早,但文中涉及的全部 MongoDB 概念及命令行工具基本適用於全部版本。github

一 簡介

瞭解 MongoDB 前先了解 NoSQL,NoSQL 是一種數據存儲系統(非關係型數據庫系統),相比 MySQL 這類關係型數據庫提供通用的數據存儲解決方案,NoSQL 傾向負責解決系統中一部分數據存儲問題。算法

MongoDB 是一種 NoSQL 解決方案,提供更加通用的 NoSQL 方案。mongodb

本文約定 Mongo 和 MongoDB 都是代指 MongoDB 數據庫系統。shell

二 準備

2.1 安裝和運行 Mongo 服務

在學習 MongoDB 以前,須要安裝 MongoDB 環境。可到 官方下載頁面 下載須要的 MongoDB 版本。數據庫

  1. Windows 操做系統能夠在 這裏 下載對應的 MongoDB 安裝包。
  2. 解壓下載的包(到任意路徑)並進入 bin 子目錄,暫且不要執行任何命令。讓我先介紹一下,mongod 將啓動服務器進程,而 mongo 會打開客戶端的 shell,——大部分時間咱們將和這兩個可執行文件打交道。
  3. bin 子目錄中建立一個新的文本文件,取名爲。
  4. mongodb.config 中加一行:
dbpath=PATH_TO_WHERE_YOU_WANT_TO_STORE_YOUR_DATABASE_FILES

例如,在 Windows 中您須要添加的多是 dbpath=c:\mongodb\data,而在Linux下可能就是 dbpath=/etc/mongodb/data。數組

  1. 確認您指定的dbpath是存在的。
  2. 執行 mongod,帶上參數--config /path/to/your/mongodb.config。命令是這樣的 mongod --config /path/to/your/mongodb.config

上面的安裝步驟用於安裝和啓動 MongoDB 服務器進程。下面以 Windows 系統爲例,講解 MongoDB 安裝及啓動詳細過程。

  1. 將安裝包解壓到 *c:mongodb*
  2. 建立 c:\mongodb\data\ 文件夾,該文件夾將用於存儲 MongoDB 的數據;
  3. 建立 c:\mongodb\bin\mongodb.config 配置文件並添加 dbpath=c:\mongodb\data\ 配置;
  4. 命令行中進入 c:\mongodb\bin 目錄,執行 c:\mongodb\bin\mongod --config c:\mongodb\bin\mongodb.config 啓動 Mongo 服務;

對於不建立 c:\mongodb\bin\mongodb.config配置的用戶,能夠經過 --dbpath 參數啓動服務,執行 c:\mongodb\bin\mongod --dbpath c:\mongodb\data\;效果和使用 --config 參數同樣。

接下來,咱們經過 SHELL 環境鏈接 MongoDB 服務。進入 c:\mongodb\bin 目錄,執行 mongo 命令,便可完成 MongoDB 服務鏈接。

須要說明的是 MongoDB 在 c:\mongodb\bin,提供了一些工具,其中就包括上去的 mongod.exemongo.exe,它們對應 mongodmongo 命令。

2.2 MongoDB 基本概念

若是有使用過關係型數據庫(如 MySQL),那麼對數據庫、表、行、字段這些概念不會陌生,在 MongoDB 中也有相似的數據結構,不過在 Mongo 中將以另外一種形式存在:

  1. 數據庫 (database)至關於 SQL 中的 database
  2. 集合 (collection)至關於 SQL 中的 table
  3. 文檔 (document)至關於 SQL 中的 row
  4. 域 (field)至關於 SQL 中的 column
  5. 索引 (index)至關於 SQL 中的 index
  6. 主鍵 (primaryKey)至關於 SQL 中的主鍵,但 MongoDB 會自動在插入(insert)數據時將 _id 域,設置爲主鍵字段

MongoDB 和 關係型數據庫相關概念關係對照表:

SQL術語/概念 MongoDB術語/概念 解釋/說明
database database 數據庫
table collection 數據庫表/集合
row document 數據記錄行/文檔
column field 數據字段/域
index index 索引
table joins 錶鏈接,MongoDB不支持
primary key primary key 主鍵,MongoDB自動將_id字段設置爲主鍵

表格信息引用自 MongoDB 概念解析

2.2.1 與數據庫、集合、文檔相關經常使用命令

下文中全部命令,需在命令終端執行。當使用 mongo 命令成功鏈接 MongoDB 服務後,可使用 help 獲取 MongoDB 數據庫使用幫助,它的執行結果大體以下:

> help
    db.help()                    help on db methods
    db.mycoll.help()             help on collection methods
    rs.help()                    help on replica set methods
    help admin                   administrative help
    help connect                 connecting to a db help
    help keys                    key shortcuts
    help misc                    misc things to know
    help mr                      mapreduce

    show dbs                     show database names
    show collections             show collections in current database
    show users                   show users in current database
    show profile                 show most recent system.profile entries with time >= 1ms
    show logs                    show the accessible logger names
    show log [name]              prints out the last segment of log in memory, 'global' is default
    use <db_name>                set current database
    db.foo.find()                list objects in collection foo
    db.foo.find( { a : 1 } )     list objects in foo where a == 1
    it                           result of the last line evaluated; use to further iterate
    DBQuery.shellBatchSize = x   set default number of items to display on shell
    exit                         quit the mongo shell

1 顯示 MongoDB 數據庫

執行 show dbs,顯示 MongoDB 全部數據庫

2 切換 MongoDB 數據庫

執行 use test,將工做數據庫切入到 test 數據庫。在 MongoDB 中沒有相似關係數據庫的 Schema 概念,因此即便 MongoDB 的數據庫未建立,也能夠任意切換工做數據庫。

3 顯示數據庫中的集合(collection)

執行 show colections,會打印輸出當前數據庫中的全部數據庫集合。

4 獲取工做數據庫幫助信息

當使用 use test 進入 test 數據庫後,能夠執行 db.help() 指令查看 database 級別支持的命令,結果以下:

> db.help()
DB methods:
        db.addUser(username, password[, readOnly=false])
        db.auth(username, password)
        db.cloneDatabase(fromhost)
        db.commandHelp(name) returns the help for the command
        db.copyDatabase(fromdb, todb, fromhost)
        db.createCollection(name, { size : ..., capped : ..., max : ... } )
        db.currentOp() displays the current operation in the db
        db.dropDatabase()
        db.eval(func, args) run code server-side
        db.getCollection(cname) same as db['cname'] or db.cname
        db.getCollectionNames()
        db.getLastError() - just returns the err msg string
        db.getLastErrorObj() - return full status object
        db.getMongo() get the server connection object
        db.getMongo().setSlaveOk() allow this connection to read from the nonmaster member of a replica pair
        db.getName()
        db.getPrevError()
        db.getProfilingLevel() - deprecated
        db.getProfilingStatus() - returns if profiling is on and slow threshold
        db.getReplicationInfo()
        db.getSiblingDB(name) get the db at the same server as this one
        db.isMaster() check replica primary status
        db.killOp(opid) kills the current operation in the db
        db.listCommands() lists all the db commands
        db.logout()
        db.printCollectionStats()
        db.printReplicationInfo()
        db.printSlaveReplicationInfo()
        db.printShardingStatus()
        db.removeUser(username)
        db.repairDatabase()
        db.resetError()
        db.runCommand(cmdObj) run a database command.  if cmdObj is a string, turns it into { cmdObj : 1 }
        db.serverStatus()
        db.setProfilingLevel(level,<slowms>) 0=off 1=slow 2=all
        db.shutdownServer()
        db.stats()
        db.version() current version of the server
        db.getMongo().setSlaveOk() allow queries on a replication slave server
        db.fsyncLock() flush data to disk and lock server for backups
        db.fsyncUnock() unlocks server following a db.fsyncLock()

5 查看工做數據庫名

須要查看當前工做的數據庫,執行以下命令

> db.getName()
test1

6 查看工做數據庫統計信息

db.stats() 會列出工做數據庫中 集合、數據庫大小等有用的信息。

> db.stats()
{
    "db":"test", --查看的是哪一個數據庫
    "collections":7, --collection數量
    "objects":28, --對象數量
    "avgObjSize":50.57142857142857, --對象平均大小
    "dataSize":1416, --數據大小
    "storageSize":31744, --數據大小(含預分配空間)
    "numExtents":7, --事件數量
    "indexes":7, --索引數量
    "indexSize":57344, --索引大小
    "fileSize":50331648, --文件大小
    "ok":1 --本次取stats是否正常
}

上例結果引用自 db.stats() - 顯示當前db狀態

7 刪除數據庫

當須要刪除 某個 數據庫時,請先使用 use 指令切換工做數據庫至待刪除數據庫。而後執行 db.dropDatabase() 指令。

> show dbs
    local   (empty)
    test    0.03125GB
    test1   (empty)

> use test1
    switched to db test1

> db.dropDatabase()
{ "dropped" : "test1", "ok" : 1 }

> show dbs
local   (empty)
test    0.03125GB

有了上面的基本概念,咱們就知道如何使用 MongoDB 的數據庫和數據集了,下面是一個小練習,來加深相關知識的使用及理解:

2.2.2 MongoDB 訓練場

場景:咱們開闢一個訓練場,將完成數據庫服務啓動、客戶端鏈接 MongoDB 服務、查看和選擇數據庫及數據庫刪除操做。

約定在 shell 中以 -- 開始的註釋說明信息:執行時請不要賦值註釋信息。

-- 1. 啓動一個 Windows 命令行窗口,開啓 MongoDB 服務

> cd c:\mongodb\bin
> mongod --config c:\mongodb\bin\mongodb.config

-- 2. 另啓動一個 Windows 命令行窗口鏈接 MongoDB 服務
> cd c:\mongodb\bin
> mongo

MongoDB shell version: 2.0.7
connecting to: test

-- 3. 查看全部數據庫
> show dbs

local   (empty)
test    0.03125GB
test1   (empty)

-- 4. 切換工做數據庫至 blog
> use blog

switched to db blog

-- 5. 查看當前工做數據庫

> db.getName()

blog

-- 6. 切換工做數據庫至 test
> use test

switched to db test

-- 7. 查看當前工做數據庫

> db.getName()

test

-- 8. 切回工做數據庫至 blog
> use blog

switched to db blog

-- 9. 查看 blog 庫的全部集合, 因爲是空數據庫因此會沒有返回信息
> show collections

-- 10 查看 blog 庫的狀態,因爲是空數據庫因此統計信息內相關數據爲空

> db.stats()
{
        "db" : "blog",
        "collections" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "nsSizeMB" : 0,
        "ok" : 1
}

-- 11. 插入一個用戶到 blog 數據庫的 user 集合裏。
-- 不知道如何插入?不要緊,直接複製下面的命令就行了。
> db.user.insert({name: 'huliuqing', age: 18, hobby: ['coding', 'reading']})

-- 12. 查看剛剛 user 集合的插入結果
> db.user.find()
{ "_id" : ObjectId("5abde35e7d318c10d73539e3"), "name" : "huliuqing", "age" : 18, "hobby" : [ "coding", "reading" ] }

-- 13. 再看下 blog 庫的狀態
> db.stats()
{
        "db" : "blog",
        "collections" : 3,
        "objects" : 5,
        "avgObjSize" : 51.2,
        "dataSize" : 256,
        "storageSize" : 16384,
        "numExtents" : 3,
        "indexes" : 1,
        "indexSize" : 8176,
        "fileSize" : 16777216,
        "nsSizeMB" : 16,
        "ok" : 1
}

-- 14. 刪除 user 集合
-- 不知道使用什麼命令?那先來查看下 user 集合層級的幫助信息吧
> db.user.help()
...
    db.user.drop() drop the collection
...

> db.user.drop()
true

-- 14. 再看下 blog 庫的狀態
{
        "db" : "blog",
        "collections" : 2,
        "objects" : 1,
        "avgObjSize" : 36,
        "dataSize" : 36,
        "storageSize" : 8192,
        "numExtents" : 2,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 16777216,
        "nsSizeMB" : 16,
        "ok" : 1
}

-- 15. 刪除 blog 數據庫
> db.dropDatabases()
{ "dropped" : "blog", "ok" : 1 }

-- 16. 再看下 blog 庫的狀態
> db.stats()
{
        "db" : "blog",
        "collections" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "nsSizeMB" : 0,
        "ok" : 1
}

-- 17 查看下數據庫
> show dbs

local   (empty)
test    0.03125GB
test1   (empty)

2.3 MongoDB 基本概念總結

  1. MongoDB 有 數據庫 組成;數據庫由 集合 組成;集合由 文檔組成;文檔包含一個或多個 ;且集合能夠被 索引,以提高 查找排序 效率。
  2. 在關係型數據庫中在數據表(table)層級定義列(column)信息;在 NoSQL 中是在 文檔 這一層定義 ,即一個集合裏的每一個文檔均可以有本身的域。
  3. MongoDB 中的集合是無模式的(schema-less),無需提早建立(即不須要像 SQL 同樣 CREATE TABLE 或 CREATE DATABASE)。
  4. 命令的分類
  • 全局命令,使用 help 查看全局命令
  • 當前數據庫級別命令,執行 db.help() 命令查看
  • 當前集合級別命令,執行 db.your_collection.help() 命令查看。

另外須要說明的是 MongoDB 的 SHELL 運行於 JavaScript 之上。除全局命令外,操做 db 數據庫、 db.COLLECTION_NAME 操做集合,若缺乏 () 將會在 SHELL 裏打印出方法的實現源碼。

三 MongoDB CRUD 操做

前面咱們學習瞭如何使用 MongoDB 的幫助,接下來在學習 CRUD 操做以前,進一步瞭解下 MongoDB 的數據庫及集合是如何建立的。

MongoDB 是 無模式 的,當使用 use YOUR_DATABASE 命令切換數據庫時,咱們無需預先建立 YOUR_DATABASE 數據庫,而當向某個 集合 插入一個 文檔 時,將會自動生成具體的數據庫、集合和文檔。

如:

> use mongo_playground
> db.users.insert({name: 'huliuqing', age: 18, gender: 'male'})

上面的命令對 users 集合作 insert(插入文檔) 操做,傳入的參數是一個 JSON 格式數據。經過 show collections 命令查看到有: userssystem.indexes 兩個集合存在,其中 system.indexes 集合會在每一個 數據庫MongoDB 自主建立,這個集合包含數據庫中的索引信息。

在執行 insert 命令時,MongoDB 會生成一個值爲 ObjectId 類型的 _id 域_id 域 對每一個 文檔 都是必須的,它相似於 SQL 的主鍵,咱們可使用本身的算法生成 _id 的值,大部分狀況下使用 MongoDB 的默認值就能夠了。

前面說過 _id 域 相似主鍵,它的索引信息被存儲在 system.indexes 集合內,咱們看看兩個集合裏有什麼數據:

-- 1. 查看集合
> show collections

system.indexes
users

-- 2. 查看 users 集合數據
> db.users.find().pretty()
{
        "_id" : ObjectId("5ac2f7ecfdcd54e4d368bde5"),
        "name" : "huliuqing",
        "age" : 18,
        "gender" : "male"
}

-- 3. 查看 system.indexes 集合數據
> db.system.indexes.find().pretty()
{
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "ns" : "mongo_playground.users",
        "name" : "_id_"
}

從結果咱們能夠看到 users 集合比添加的 JSON 多了 _id 域,它的索引信息被 system.indexes 集合記錄。

3.1 CRUD - CREATE 建立 MongoDB 數據

建立一個 文檔db.YOUR_COLLECTION.insert() 命令完成,咱們向 db.users 集合插入一條新的文檔:

-- 1. 建立文檔
> db.users.insert({name: 'zhangsanfeng', age: 120, gender: 'male', hobby: ['Kung fu', 'Tai Chi']});

-- 2. 查詢結果
> db.users.find()
{ "_id" : ObjectId("5ac2f7ecfdcd54e4d368bde5"), "name" : "huliuqing", "age" : 18, "gender" : "male" }
{ "_id" : ObjectId("5ac3165bfdcd54e4d368bde6"), "name" : "zhangsanfeng", "age" : 120, "gender" : "male", "hobby" : [ "Kung fu", "Tai Chi" ] }

3.2 CRUD - RETRIEVE 查詢 MongoDB 數據

一個簡單的查詢操做可使用 db.YOUR_COLLECTION.find() 指令來獲取全部 YOUR_COLLECTION 集合的全部文檔列表。除此以外,咱們還須要知道在 MongoDB 中有個 查詢構造器 的概念,查詢構造器 相似於 SQL 中的 WHERE 語句

查詢構造器

在學習查詢構造器以前,咱們先清洗下 mongo_playground 數據庫,並加入測試集合。

-- 1. 進入 mongo_playground 數據庫
> use mongo_playground

-- 2. 刪除 mongo_playground 數據庫
> db.dropDatabase()

-- 3. 建立測試數據
db.users.insert({name: 'Bob',birthday: new Date(1992,2,13,7,47),hobby: ['basketball','football'],weight: 60,gender: 'm',age: 18});
db.users.insert({name: 'John',birthday: new Date(1991, 0, 24, 13, 0),hobby: ['basketball', 'ping pong'],weight: 45,gender: 'm',age: 23});
db.users.insert({name: 'Tony',birthday: new Date(1973, 1, 9, 22, 10),hobby: ['boxing', 'racing'],weight: 98,gender: 'm',age: 30});
db.users.insert({name: 'Lily',birthday: new Date(1997, 6, 1, 10, 42),hobby: ['ping pong', 'yoga'],weight: 69,gender: 'f',age: 39});
db.users.insert({name: 'Jack',birthday: new Date(1979, 7, 18, 18, 44),hobby: ['skiing'],weight: 57,gender: 'm',age: 51});
db.users.insert({name: 'Tom',birthday: new Date(1985, 6, 4, 2, 1),hobby:['skiing', 'basketball','boxing'],weight:65,gender:'m',age:29});
db.users.insert({name: 'Jackson',birthday: new Date(1998, 2, 7, 8, 30),hobby: ['skateboard', 'running'],weight: 73,gender: 'f',age: 41});
db.users.insert({name: 'Lucy',birthday: new Date(2005, 4, 3, 0, 57),hobby: ['skiing', 'yoga'],weight: 42,gender: 'f',age: 22});
db.users.insert({name: 'Peter',birthday: new Date(2001, 9, 8, 14, 53),hobby: ['shooting', 'darts'],weight: 60,gender: 'm',age: 48});
db.users.insert({name: 'Rose',birthday: new Date(1997, 2, 1, 5, 3),hobby: ['shooting', 'darts'],weight: 65,gender: 'f',age: 56});
db.users.insert({name: 'Lee',birthday: new Date(1999, 11, 20, 16, 15),hobby: ['ping pong', 'basketball'],weight: 54,gender: 'm'});

3.2.1 條件查詢

3.2.1.1 基礎條件查詢 {fieldName: value}

查找用戶 name 等於 Lee 的信息

> db.users.find({name: 'Lee'}).pretty()
{
        "_id" : ObjectId("5ac31e00fdcd54e4d368bdfc"),
        "name" : "Lee",
        "birthday" : ISODate("1999-12-20T08:15:00Z"),
        "hobby" : [
                "ping pong",
                "basketball"
        ],
        "weight" : 54,
        "gender" : "m"
}

3.2.1.2 查詢 {fieldName1:value1, fieldName2:value2}

查找喜歡 跑步男性

> db.users.find({gender: 'm', hobby: 'racing'}).pretty()
{
        "_id" : ObjectId("5ac31e00fdcd54e4d368bdf4"),
        "name" : "Tony",
        "birthday" : ISODate("1973-02-09T14:10:00Z"),
        "hobby" : [
                "boxing",
                "racing"
        ],
        "weight" : 98,
        "gender" : "m",
        "age" : 30
}

3.2.1.3 查詢 {$or: [{fieldName: value1}, {fieldName: value2}]}

查找喜歡 乒乓球瑜伽男性

-- 1. 僅查找喜歡 乒乓球 或 瑜伽 的用戶
> db.users.find({gender: 'm', $or: [{hobby: 'ping pong'}, {hobby: 'yoga'}]})

{ "_id" : ObjectId("5ac327edfdcd54e4d368be09"), "name" : "John", "birthday" : ISODate("1991-01-24T05:00:00Z"), "hobby" : [ "basketball", "ping pong" ], "weight" : 45, "gender" : "m", "age" : 23 }
{ "_id" : ObjectId("5ac327edfdcd54e4d368be12"), "name" : "Lee", "birthday" : ISODate("1999-12-20T08:15:00Z"), "hobby" : [ "ping pong", "basketball" ], "weight" : 54, "gender" : "m" }

-- 2. 下面的查找將查找到全部的喜歡 乒乓球 或 瑜伽 的用戶
> db.users.find({$or: [{hobby: 'ping pong'}, {hobby: 'yoga'}]})

3.2.1.4 比較查詢

經過 $lt(less than: 小於)**、**$lte(less than and equal: 小於等於)$gt(greater than: 大於)**、**$gte(greater than and equal: 大於等於)$ne(not equal: 不等於) 等實現比較查詢。

-- 1. 查詢年齡大於等於 30 歲且小於  40 歲的用戶
> db.users.find({age: {$gte: 30, $lt: 40}})

-- 2. 查詢年齡大於 55 歲的用戶
> db.users.find({age: {$gt: 55}})

-- 3. 查詢年齡小於 18 歲的用戶
> db.users.find({age: {$lt: 20}})

-- 4. 查詢年齡不等於 18 歲的用戶
> db.users.find({age: {$ne: 18}})

3.2.1.5 判斷文檔中是否存在某個域

3.2.1.4 的第 4 個示例 4. 查詢年齡不等於 18 歲的用戶 會查詢到沒有 age 域的用戶 Lee。經過 $exists 指令能夠判斷某個域是否存在,它的值是 bool 類型,咱們對這個示例作些改進:

-- 1. 查詢年齡字段存在且年齡不等於 18 歲的用戶
> db.users.find({age: {$ne: 18, $exists: true}})

3.2 總結

本章瞭解了 MongoDB 相關查詢操做,瞭解更多查詢命令細節能夠查看 查詢文檔。但更重要的是反覆練習這些查詢語句的基本用法。

3.3 CRUD - UPDATE 更新 MongoDB 數據

MongoDB 的更新須要特別關注一下,更新數據使用 db.YOUR_COLLECTIONS.update(query, object, options) 方法,update 接收兩個必選參數:查詢選擇器須要更新的域

3.3.1 UPDATE 覆蓋 與 UPDATE $set 更新

一個簡單的示例,咱們找到 年齡 48 歲 的用戶 Peter,將他的年齡 更新爲 49 歲

> db.users.find({age: 48}).pretty()
{
        "_id" : ObjectId("5ac42ff514c16270040db426"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 48
}

> db.users.update({age: 48}, {age: 49})

> db.users.find({age: 49}).pretty()
{ "_id" : ObjectId("5ac42ff514c16270040db426"), "age" : 49 }

再次查找 年齡 49 歲 的用戶,會發現 更新後 Perter 用戶數據被 覆蓋{ "_id" : ObjectId("5ac42ff514c16270040db426"), "age" : 49 }(由於 ObjectId 相同)。

這是由於: 在 MongoDB 中接收的第二個參數,若是沒有使用 $set 修飾符,將會採起 覆蓋 文檔操做,而不是 更新文檔指定域,這和 SQL 的 UPDATE 語句行爲不同。

正確的更新 應該是下面的 update 寫法使用 {$set: {age: 49}},操做以前咱們要清空並重建測試數據。

> db.users.find({age: 48}).pretty()
{
        "_id" : ObjectId("5ac42ff514c16270040db426"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 48
}

> db.users.update({age: 48}, {$set: {age: 49}})

> db.users.find({age: 49}).pretty()
{
        "_id" : ObjectId("5ac4375b14c16270040db43c"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 49
}

建議: 在執行 刪除更新 這類操做前,建議先採用相同的查詢條件查找數據,結果與判斷一致時再作 刪除更新 等操做。

3.3.2 UPDATE $inc 和 $push 修飾符

  • $inc 修飾符,對文檔中的某個域增長一個 正值負值
  • $push 修飾符,向域的值爲數組中添加新值。
-- 1. Peter 又長大了一歲
> db.users.find({name: 'Peter'})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "name" : "Peter", "birthday" : ISODate("2001-10-08T06:53:00Z"), "hobby" : [ "shooting", "darts" ], "weight" : 60, "gender" : "m", "age" : 49 }
> db.users.update({name: 'Peter'}, {$inc: {age: 1}})

-- 2. Peter 越活越年輕
> db.users.find({name: 'Peter'})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "name" : "Peter", "birthday" : ISODate("2001-10-08T06:53:00Z"), "hobby" : [ "shooting", "darts" ], "weight" : 60, "gender" : "m", "age" : 50 }

> db.users.update({name: 'Peter'}, {$inc: {age: -5}})

-- 3. 由於 Peter 有了更多的興趣愛好
> db.users.update({name: 'Peter'}, {$push: {hobby: 'racing'}})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "age" : 45, "birthday" : ISODate("2001-10-08T06:53:00Z"), "gender" : "m", "hobby" : [ "shooting", "darts", "racing" ], "name" : "Peter", "weight" : 60 }

3.3.3 UPDATE upsert 選項: 插入新文檔或更新文檔域數據

MongoDB update 方法第三個參數接收 bool 值的標識符,該值默認爲 false。當該值設爲 true 時若 查詢選擇器 的目標文檔存在,則採起 update $set 域 操做;若不存在則採起 INSERT 操做。

這個選項在相似 網站點擊計數器 統計場景中很是有用。若是網頁點擊記錄存在則更新記錄數,不存在則執行插入操做。

-- 1. 給 users 頁面統計點擊數, update 第三個參數爲 false 或 缺省,將不會建立 hits 集合
> db.hits.update({page: 'users'}, {$inc: {hits: 1}})
> db.hits.find()

-- 2. upsert 選項設置爲 true,在執行 update 更新操做時,hits 集合未建立,執行建立操做
> db.hits.update({page: 'users'}, {$inc: {hits: 1}}, {upsert: true})
> db.hits.find()
{ "_id" : ObjectId("5ac4427bb5b4350bc6d2f715"), "hits" : 1, "page" : "users" }

-- 3. upsert 選項設置爲 true,在執行 update 更新操做時,hits 集合已建立,執行更新操做
> db.hits.update({page: 'users'}, {$inc: {hits: 1}}, {upsert: true})
> db.hits.find()
{ "_id" : ObjectId("5ac4427bb5b4350bc6d2f715"), "hits" : 2, "page" : "users" }

3.3.4 批量更新

MongoDB update 操做在 3.3.1 介紹過,更新數據須要 $set 修飾符,不然執行覆蓋操做。這裏咱們介紹它的第二個獨特特性:默認更新一條記錄

當咱們須要給全部用戶加上點贊數 likes 域用於記錄用戶獲得的贊,咱們會想下面的方法同樣執行,但僅僅只有一條文檔加上了 likes 域:

> db.users.update({}, {$set:{likes: 0}})
> db.users.find({likes: 0})

multi 選項值設爲 true 能夠實現全部文檔記錄新增 操做。

> db.users.update({}, {$set:{likes: 0}}, false, true)
> db.users.find({likes: 0})

能夠在文檔查看 update 方法相關具體使用。

3.4 CRUD - DELETE 刪除 MongoDB 數據

經過 db.YOUR_COLLECTION.remove(query, justOne) 能夠刪除一個或全部 文檔,參數接收的查詢選擇器爲空時刪除全部文檔,當 justOne 標識爲 true 是僅刪除一條匹配文檔。

-- 1. 刪除用戶 Bob 的記錄
> db.users.find({name: 'Bob'})
> db.users.remove({name: 'Bob'})
> db.users.find({name: 'Bob'})

-- 2. 刪除全部用戶
> db.users.find()
> db.users.remove()
> db.users.find()

相關細節能夠查閱 刪除文檔

若是須要刪除全部文檔,咱們還能夠經過 db.YOUR_COLLECTIONS.drop() 方法實現,drop() 方法不只刪除全部文檔還會刪除該集合的索引信息。

3.5 CRUD - 重識 RETRIEVE 查詢 MongoDB 數據

咱們在 3.2 章節中瞭解了有關 MongoDB 的查詢功能。本節咱們將學習包括查詢指定域、排序、返回的結果集記錄數限制和分頁等功能,這些方法在應用程序開發過程當中會十分常見。

3.5.1 返回指定域

在 Mongo Shell 裏咱們經過 db.YOUR_COLLECTION.find 注意 無 () 能夠看到 find 方法的具體實現,find 一共能夠接收 4 個參數:第一個參數是查詢選擇器;第二個參數即爲指定返回的域。

以前,咱們都是返會全部的域信息,如今讓咱們僅返回用戶的用戶名、年齡和性別:

> db.users.find({}, {name: true, age: true, gender: true})
{ "_id" : ObjectId("5acada245c193d1acc967575"), "name" : "Bob", "gender" : "m", "age" : 18 }
{ "_id" : ObjectId("5acada245c193d1acc967576"), "name" : "John", "gender" : "m", "age" : 23 }
{ "_id" : ObjectId("5acada245c193d1acc967577"), "name" : "Tony", "gender" : "m", "age" : 30 }
...

默認 _id 域總會做爲查詢結果返回,能夠設置 {_id: falsee} 顯示的排除掉。

3.5.2 排序

在 MongoDB 中咱們還須要瞭解一個基本概念 遊標(cursor),因爲前面咱們並無涉及到遊標的使用(只是看起來沒有涉及到遊標)。

find 方法返回的結果即爲依據查詢選擇器匹配到的文檔集合的 遊標,這樣能夠經過鏈式操做對 find 結果集進行處理。

咱們在 MongoDB Shell 裏輸入 db.users.help() 命令能夠看到下面的幫助信息:

> db.users.help()
...
        db.users.find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return.
                                                      e.g. db.users.find( {x:77} , {name:1, x:1} )
        db.users.find(...).count()
        db.users.find(...).limit(n)
        db.users.find(...).skip(n)
        db.users.find(...).sort(...)
...

countlimitskipsort 等方法便是做用在 find 返回的遊標上。

下面咱們依據用戶的年齡按照 升序降序 排列:

-- 1. 依據升序排列
> db.users.find({}, {name: 1, age: 1}).sort({age: 1})

-- 2. 依據降序排列
> db.users.find({}, {name: 1, age: 1}).sort({age: -1})

3.5.3 分頁

要實現分頁功能須要結合使用 skip(n)limit(n) 兩個方法,它們的返回值也是一個遊標。skip 會選擇遊標的起始位置,limit 相似 SQL 的 limit 語句表示返回的結果集最大紀錄條數。

下面咱們查下年齡第二和第三大的用戶:

-- 1. 先看下年齡最大的 5 名用戶
> db.users.find({}, {name: true, age: 1}).sort({age: -1}).limit(5)

-- 2. 再看下年齡第二和第三大的用戶
> db.users.find({}, {name: true, age: 1}).sort({age: -1}).skip(1).limit(2)

3.5.4 查詢集合記錄數

在 MongoDB 中能夠直接使用 db.YOUR_COLLECTION.count() 方法獲取集合記錄數,也能夠經過 db.YOUR_COLLECTION.find().count() 獲取:

獲取年齡大於等於 20 歲的用戶數:

> db.users.count({age: {$gte: 20}})
> db.users.find({age: {$gte: 20}}).count()

可是要知道 db.YOUR_COLLECTION.count() 僅僅是 db.YOUR_COLLECTION.find().count() 的別名,在它的內部仍是調用 db.YOUR_COLLECTION.find().count()

> db.users.count
function (x) {
    return this.find(x).count();
}

更多有關做用於遊標的方法能夠查閱 遊標方法

TO BE CONTINUE

相關文章
相關標籤/搜索