小白必須懂的MongoDB的總結
一、MongoDB的認識
1、什么是MongoDB?
MongoDB
是一個介於關系數據庫和非關系數據庫之間的開源產品,是最接近於關系型數據庫的 NoSQL
數據庫。它在輕量級JSON
交換基礎之上進行了擴展,即稱為 BSON
的方式來描述其無結構化的數據類型。盡管如此它同樣可以存儲較為復雜的數據類型。它和上一篇文章講到的Redis有異曲同工之妙。雖然兩者均為 NoSQL
,但是 MongoDB
相對於 Redis
而言,MongoDB
更像是傳統的數據庫。早些年我們是先有了 Relation Database
(關系型數據庫),然后出現了很多很復雜的query
,里面用到了很多嵌套,很多 join
操作。所以在設計數據庫的時候,我們也考慮到了如何應用他們的關系,使得寫 query
可以使 database
效率達到最高。后來人們發現,不是每個系統,都需要如此復雜的關系型數據庫。有些簡單的網站,比如博客,比如社交網站,完全可以斬斷數據庫之間的一切關系。這樣做帶來的好處是,設計數據庫變得更加簡單,寫 query
也變得更加簡單。然后,query
消耗的時間可能也會變少。因為 query
簡單了,少了許多消耗資源的 join
操作,速度自然會上去。正如所說的, query
簡單了,很有以前 MySQL
可以找到的東西,現在關系沒了,通過 Mongo
找不到了。我們只能將幾組數據都抓到本地,然后在本地做 join
,所以在這點上可能會消耗很多資源。這里我們可以發現。如何選擇數據庫,完全取決於你所需要處理的數據的模型,即 Data Model
。如果它們之間,關系錯綜復雜,千絲萬縷,這個時候 MySQL
一定是首選。如果他們的關系並不是那么密切,那么, NoSQL
將會是利器。
MongoDB
和 Redis
一樣均為 key-value
存儲系統,它具有以下特點:
-
面向集合存儲,易存儲對象類型的數據。
-
模式自由。
-
支持動態查詢。
-
支持完全索引,包含內部對象。
-
支持查詢。
-
支持復制和故障恢復。
-
使用高效的二進制數據存儲,包括大型對象(如視頻等)。
-
自動處理碎片,以支持雲計算層次的擴展性
-
支持
Python
,PHP
,Ruby
,Java
,C
,C#
,Javascript
,Perl
及C++
語言的驅動程序,社區中也提供了對Erlang
及.NET
等平台的驅動程序。 -
文件存儲格式為
BSON
(一種JSON
的擴展)。 -
可通過網絡訪問。
2、MongoDB與MySQL性能比較
像 MySQL
一樣, MongoDB
提供了豐富的遠遠超出了簡單的鍵值存儲中提供的功能和功能。 MongoDB
具有查詢語言,功能強大的輔助索引(包括文本搜索和地理空間),數據分析功能強大的聚合框架等。相比使用關系數據庫而言,使用MongoDB
,您還可以使用如下表所示的這些功能,跨越更多樣化的數據類型和數據規模。
MySQL |
MongoDB |
|
---|---|---|
豐富的數據模型 | 否 | 是 |
動態 Schema |
否 | 是 |
數據類型 | 是 | 是 |
數據本地化 | 否 | 是 |
字段更新 | 是 | 是 |
易於編程 | 否 | 是 |
復雜事務 | 是 | 否 |
審計 | 是 | 是 |
自動分片 | 否 | 是 |
MySQL
中的許多概念在 MongoDB
中具有相近的類比。本表概述了每個系統中的一些常見概念。
MySQL |
MongoDB |
---|---|
表 | 集合 |
行 | 文檔 |
列 | 字段 |
joins |
嵌入文檔或者鏈接 |
3、應用范圍和限制
MongoDB
的主要目標是在 key-value
(鍵/值)存儲方式(提供了高性能和高度伸縮性)以及傳統的 RDBMS
系統(豐富的功能)架起一座橋梁,集兩者的優勢於一身。 MongoDB
適用范圍如下:
-
網站數據:
Mongo
非常適合實時的插入,更新與查詢,並具備網站實時數據存儲所需的復制及高度伸縮性。 -
緩存:由於性能很高,
Mongo
也適合作為信息基礎設施的緩存層。在系統重啟之后,由Mongo
搭建的持久化緩存層可以避免下層的數據源過載。 -
大尺寸,低價值的數據:使用傳統的關系型數據庫存儲一些數據時可能會比較昂貴,在此之前,很多時候程序員往往會選擇傳統的文件進行存儲。
-
高伸縮性的場景:
Mongo
非常適合由數十或數百台服務器組成的數據庫。Mongo
的路線圖中已經包含對MapReduce
引擎的內置支持。 -
用於對象及 JSON 數據的存儲:
Mongo
的BSON
數據格式非常適合文檔化格式的存儲及查詢。
MongoDB
當然也會有以下場景的限制:
-
高度事物性的系統:例如銀行或會計系統。傳統的關系型數據庫目前還是更適用於需要大量原子性復雜事務的應用程序。
-
傳統的商業智能應用:針對特定問題的
BI
數據庫會對產生高度優化的查詢方式。對於此類應用,數據倉庫可能是更合適的選擇。 -
需要
SQL
的問題。
二、MongoDB的安裝
環境准備
-
CentOS7
安裝步驟
1、創建一個 mongodb-org-3.6.repo
文件
vi /etc/yum.repos.d/mongodb-org-3.6.repo
在文件中加入如下內容:
[mongodb-org-3.6]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.6/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
退出編輯模式,直接輸入如下命令安裝即可:
sudo yum install -y mongodb-org
若要安裝特定版本的 MongoDB
,請分別指定每個組件包並將版本號附加到包名稱,如下所示:
sudo yum install -y mongodb-org-3.6.3 mongodb-org-server-3.6.3 mongodb-org-shell-3.6.3 mongodb-org-mongos-3.6.3 mongodb-org-tools-3.6.3
你可以指定任何可用的 MongoDB
版本。然而, yum
會在新版本可用時升級軟件包。為防止意外升級,請釘住包裝。要固定軟件包,請將以下 exclude
指令添加到 /etc/yum.conf
文件中:
exclude=mongodb-org,mongodb-org-server,mongodb-org-shell,mongodb-org-mongos,mongodb-org-tools
我們直接運行如下命令:
mongod -repair
看到如下字樣,說明我們安裝成功!
我們創建一個 db
,並查看下 mongo
的安裝位置:
mkdir db
whereis mongod
安裝完成后啟動 mongodb
,並查看下 mongob
啟動狀態:
systemctl start mongod.service
systemctl status mongod.service
如果出現如下字樣,說明啟動成功!
成功啟動 MongoDB
后,新建一個命令行輸入 mongo
進行登錄操作,即可進行數據庫的一些操作了。
mongo
三、MongoDB數據類型及常用命令講解
MongoDB
的數據類型大致有下列幾種:
數據類型 | 描述 |
---|---|
String |
字符串。存儲數據常用的數據類型。在 MongoDB 中,UTF-8 編碼的字符串才是合法的。 |
Integer |
整型數值。用於存儲數值。根據你所采用的服務器,可分為 32 位或 64 位。 |
Boolean |
布爾值。用於存儲布爾值(真/假)。 |
Double |
雙精度浮點值。用於存儲浮點值。 |
Min/Max keys |
將一個值與 BSON (二進制的 JSON )元素的最低值和最高值相對比。 |
Arrays |
用於將數組或列表或多個值存儲為一個鍵。 |
Timestamp |
時間戳。記錄文檔修改或添加的具體時間。 |
Object |
用於內嵌文檔。 |
Null |
用於創建空值。 |
Symbol |
符號。該數據類型基本上等同於字符串類型,但不同的是,它一般用於采用特殊符號類型的語言。 |
Date |
日期時間。用 UNIX 時間格式來存儲當前日期或時間。你可以指定自己的日期時間:創建 Date 對象,傳入年月日信息。 |
Object ID |
對象 ID 。用於創建文檔的 ID 。 |
Binary Data |
二進制數據。用於存儲二進制數據。 |
Code |
代碼類型。用於在文檔中存儲 JavaScript 代碼。 |
Regular expression |
正則表達式類型。用於存儲正則表達式。 |
下面我們將介紹一些 MongoDB
的常用命令!
1、創建數據庫
use 數據庫名稱
:創建一個新的數據庫。注意:如果該數據庫不存在,則創建,如果該數據庫存在,則是切換
如果創建了數據庫,沒有任何的操作,則會自動刪除該數據庫
example:
> use stu
switched to db stu
2、查看數據庫
show dbs
:查看當前有多少個數據庫
example:
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
3、創建集合
db.集合名.insert({})
:向集合里面,添加文檔。{}
里面是 json
的文檔。注意: mongodb
里面的集合是隱式創建,就是無需創建,直接使用。 db
表示顯示當前所在的數據庫。
example:
> db.php.insert({"name":"xiaoming","age":20,"email":"xiaoming@gmail.com"})
WriteResult({ "nInserted" : 1 })
> db.php.insert({"name":"xiaohong","age":18,"email":"xiaohong@gmail.com"})
WriteResult({ "nInserted" : 1 })
4、查看集合
show tables
:查看當前數據庫中的集合
example:
> show tables
php
5、查詢集合里面的文檔
db.集合名.find()
:查詢當前數據庫中該集合下的所有文檔
example:
> db.php.find()
{ "_id" : ObjectId("5b9318ac487b851e62879578"), "name" : "xiaoming", "age" : 20, "email" : "xiaoming@gmail.com" }
{ "_id" : ObjectId("5b9319a2487b851e62879579"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" }
db.集合名.find
:查詢當前數據庫中該集合下的第一個文檔
example:
> db.php.find
function (query, fields, limit, skip, batchSize, options) {
var cursor = new DBQuery(this._mongo,
this._db,
this,
this._fullName,
this._massageObject(query),
fields,
limit,
skip,
batchSize,
options || this.getQueryOptions());
{
const session = this.getDB().getSession();
const readPreference = session._serverSession.client.getReadPreference(session);
if (readPreference !== null) {
cursor.readPref(readPreference.mode, readPreference.tags);
}
const readConcern = session._serverSession.client.getReadConcern(session);
if (readConcern !== null) {
cursor.readConcern(readConcern.level);
}
}
return cursor;
}
6、刪除集合
db.集合名.drop()
:刪除當前數據庫中的集合
example:
> db.php.drop()
true
7、刪除數據庫
db.dropDatabase()
:刪除當前的數據庫
> db.dropDatabase()
{ "dropped" : "stu", "ok" : 1 }
8、幫助命令
help
:全局幫助命令
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
sh.help() sharding helpers
rs.help() replica set helpers
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 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
db.help()
:數據庫相關的幫助命令
example:
> db.help()
DB methods:
db.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]
db.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor
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.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})
db.createUser(userDocument)
db.currentOp() displays currently executing operations in the db
db.dropDatabase()
db.eval() - deprecated
db.fsyncLock() flush data to disk and lock server for backups
db.fsyncUnlock() unlocks server following a db.fsyncLock()
db.getCollection(cname) same as db['cname'] or db.cname
db.getCollectionInfos([filter]) - returns a list that contains the names and options of the db's collections
db.getCollectionNames()
db.getLastError() - just returns the err msg string
db.getLastErrorObj() - return full status object
db.getLogComponents()
db.getMongo() get the server connection object
db.getMongo().setSlaveOk() allow queries on a replication slave server
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.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set
db.hostInfo() get details about the server's host
db.isMaster() check replica primary status
db.killOp(opid) kills the current operation in the db
db.listCommands() lists all the db commands
db.loadServerScripts() loads all the scripts in db.system.js
db.logout()
db.printCollectionStats()
db.printReplicationInfo()
db.printShardingStatus()
db.printSlaveReplicationInfo()
db.dropUser(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.setLogLevel(level,)
db.setProfilingLevel(level,slowms) 0=off 1=slow 2=all
db.setWriteConcern() - sets the write concern for writes to the db
db.unsetWriteConcern() - unsets the write concern for writes to the db
db.setVerboseShell(flag) display extra information in shell output
db.shutdownServer()
db.stats()
db.version() current version of the server
db.集合名.help()
:集合相關的幫助命令
example:
> db.php.help()
DBCollection help
db.php.find().help() - show DBCursor help
db.php.bulkWrite( operations, ) - bulk execute write operations, optional parameters are: w, wtimeout, j
db.php.count( query = {}, ) - count the number of documents that matches the query, optional parameters are: limit, skip, hint, maxTimeMS
db.php.copyTo(newColl) - duplicates collection by copying all documents to newColl; no indexes are copied.
db.php.convertToCapped(maxBytes) - calls {convertToCapped:'php', size:maxBytes}} command
db.php.createIndex(keypattern[,options])
db.php.createIndexes([keypatterns], )
db.php.dataSize()
db.php.deleteOne( filter, ) - delete first matching document, optional parameters are: w, wtimeout, j
db.php.deleteMany( filter, ) - delete all matching documents, optional parameters are: w, wtimeout, j
db.php.distinct( key, query, ) - e.g. db.php.distinct( 'x' ), optional parameters are: maxTimeMS
db.php.drop() drop the collection
db.php.dropIndex(index) - e.g. db.php.dropIndex( "indexName" ) or db.php.dropIndex( { "indexKey" : 1 } )
db.php.dropIndexes()
db.php.ensureIndex(keypattern[,options]) - DEPRECATED, use createIndex() instead
db.php.explain().help() - show explain help
db.php.reIndex()
db.php.find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return.
e.g. db.php.find( {x:77} , {name:1, x:1} )
db.php.find(...).count()
db.php.find(...).limit(n)
db.php.find(...).skip(n)
db.php.find(...).sort(...)
db.php.findOne([query], [fields], [options], [readConcern])
db.php.findOneAndDelete( filter, ) - delete first matching document, optional parameters are: projection, sort, maxTimeMS
db.php.findOneAndReplace( filter, replacement, ) - replace first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument
db.php.findOneAndUpdate( filter, update, ) - update first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument
db.php.getDB() get DB object associated with collection
db.php.getPlanCache() get query plan cache associated with collection
db.php.getIndexes()
db.php.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )
db.php.insert(obj)
db.php.insertOne( obj, ) - insert a document, optional parameters are: w, wtimeout, j
db.php.insertMany( [objects], ) - insert multiple documents, optional parameters are: w, wtimeout, j
db.php.mapReduce( mapFunction , reduceFunction , )
db.php.aggregate( [pipeline], ) - performs an aggregation on a collection; returns a cursor
db.php.remove(query)
db.php.replaceOne( filter, replacement, ) - replace the first matching document, optional parameters are: upsert, w, wtimeout, j
db.php.renameCollection( newName , ) renames the collection.
db.php.runCommand( name , ) runs a db command with the given name where the first param is the collection name
db.php.save(obj)
db.php.stats({scale: N, indexDetails: true/false, indexDetailsKey: , indexDetailsName: })
db.php.storageSize() - includes free space allocated to this collection
db.php.totalIndexSize() - size in bytes of all the indexes
db.php.totalSize() - storage allocated for all data and indexes
db.php.update( query, object[, upsert_bool, multi_bool] ) - instead of two flags, you can pass an object with fields: upsert, multi
db.php.updateOne( filter, update, ) - update the first matching document, optional parameters are: upsert, w, wtimeout, j
db.php.updateMany( filter, update, ) - update all matching documents, optional parameters are: upsert, w, wtimeout, j
db.php.validate( ) - SLOW
db.php.getShardVersion() - only for use with sharding
db.php.getShardDistribution() - prints statistics about data distribution in the cluster
db.php.getSplitKeysForChunks( ) - calculates split points over all chunks and returns splitter function
db.php.getWriteConcern() - returns the write concern used for any operations on this collection, inherited from server/db if set
db.php.setWriteConcern( ) - sets the write concern for writes to the collection
db.php.unsetWriteConcern( ) - unsets the write concern for writes to the collection
db.php.latencyStats() - display operation latency histograms for this collection
四、增刪改查操作
1、添加文檔
db.集合名.insert({k1:v1,k2:v2...})
:向當前數據庫的該集合下添加文檔
我們在添加文檔的時候有如下注意點:
a) 文檔就是鍵值對,數據類型是 BSON
格式,支持的值更加豐富。 BSON
是 JSON
的擴展,新增了諸如日期,浮點等 JSON
不支持的數據類型。
b) 在添加的文檔里面,都有一個 '_id'
的鍵,值為對象類型 ObjectID
,在這里,我們解釋下 ObjectID
類型:
每個文檔都有一個 _id
字段,並且同一集合中的 _id
值唯一,該字段可以是任意類型的數據,默認是一個 ObjectID
對象。
ObjectID
對象數據組成:時間戳|機器碼|PID|計數器
_id
的鍵值我們可以自己輸入,但是不能重復,但要注意的一點是在插入數據的時候,如果 _id
的值重復則會報錯
c) 可以使用 js
代碼來完成批量插入文檔
example:
> for(var i=1;i<=10;i++){
... db.php.insert({'name':'xiaobai'+i,'age':i,'email':'xiaobai'+i+'@gmail.com'})
... }
WriteResult({ "nInserted" : 1 })
> db.php.find()
{ "_id" : ObjectId("5b931b74a39e4f4842ba36b3"), "name" : "xiaoming", "age" : 20, "email" : "xiaoming@gmail.com" }
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36b5"), "name" : "xiaobai1", "age" : 1, "email" : "xiaobai1@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36b6"), "name" : "xiaobai2", "age" : 2, "email" : "xiaobai2@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36b7"), "name" : "xiaobai3", "age" : 3, "email" : "xiaobai3@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36b8"), "name" : "xiaobai4", "age" : 4, "email" : "xiaobai4@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36b9"), "name" : "xiaobai5", "age" : 5, "email" : "xiaobai5@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }
2、刪除文檔
db.集合名.remove{(條件)}
:刪除當前數據庫下指定集合中滿足條件的文檔(不寫條件則刪除所有的文檔)
example:
> db.php.remove({age:20})
WriteResult({ "nRemoved" : 1 })
> db.php.remove({age:{'$lt':6}})
WriteResult({ "nRemoved" : 5 })
> db.php.find()
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }
這里我們在刪除 php
集合中年齡小於6的文檔時,我們使用了操作符來完成。
比較運算符
操作符 | 效果 |
---|---|
$gt |
大於 |
$lt |
小於 |
$gte |
大於等於 |
$lte |
小於等於 |
$exists |
存在與否 |
$in |
包含 |
$ne |
不等於 |
$nin |
不包含 |
邏輯運算符
操作符 | 效果 |
---|---|
$exists |
存在與否 |
$or |
或者 |
$and |
並且 |
$not |
不存在 |
$mod |
求模 |
$where |
位置 |
特別的 $exists: true 表示字段存在
排序 sort
操作 | 效果 |
---|---|
$asc |
升序 |
$desc |
降序 |
3、更新文檔
更新文檔有兩種方式進行修改
方法一、直接修改
db.集合名.update({條件},{新的文檔})
:修改當前數據庫下指定集合中滿足條件的文檔信息
example:
> db.php.find()
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" }
> db.php.update({age:18},{name:'xiaobai5'})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.php.find()
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
db.集合.update(條件,新文檔,是否新增,是否修改多條)
:修改當前數據庫下指定集合中滿足條件的文檔信息
-
是否新增:如果值是1(true)則沒有滿足條件的 則添加
-
是否修改多條:若值是1(true),如果滿足條件的有多個文檔 則都要修改
example:
> db.php.update({age:10},{name:'xiaoli'},true,true)
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 9,
"errmsg" : "multi update only works with $ operators"
}
})
方法二、使用修改器
example:
我們要修改 age=6
的文檔名稱為 xiaosan
,並且其他鍵值不能丟失
我們可以使用修改器
-
$inc
:加上一個數字 -
$set
:修改某一個字段,如果該字段不存在就增這個字段
語法:db.集合名.update({條件},{修改器名稱:{修改的鍵:修改的新值}})
> db.php.update({age:6},{'$set':{name:'xiaosan'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
那如果我們要修改 age=10
的文檔的年齡增加十歲,我們可以這樣做:
> db.php.update({age:10},{$inc:{age:10}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
4、查詢文檔
語法: db.集合名.find({條件})
example:
取出 php
集合里面的第一個文檔
> db.php.findOne()
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
取出 php
集合里面 age=6
的文檔
> db.php.find({age:6})
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" }
取出 php
集合里面 age>8
的文檔
> db.php.find({age:{'$gt':8}})
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 20, "email" : "xiaobai10@gmail.com" }
取出 php
集合里面的文檔,只顯示 name
鍵
> db.php.find({},{age:1})//1表示只顯示age鍵值
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4") }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "age" : 6 }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "age" : 7 }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "age" : 8 }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "age" : 9 }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "age" : 20 }
> db.php.find({},{age:0})//1表示除了顯示age鍵值,其他的都顯示
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "email" : "xiaobai6@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "email" : "xiaobai7@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "email" : "xiaobai8@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "email" : "xiaobai9@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "email" : "xiaobai10@gmail.com" }
根據年齡的(降序|升序)來顯示文檔
db.集合名.find().sort({age:1})根據年齡升序
db.集合名.find().sort({age:0})根據年齡降序
顯示 php
集合中的前三個文檔
> db.php.find().limit(3)
{ "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }
顯示 php
集合中的第三個文檔到第五個文檔
> db.php.find().skip(2).limit(3)
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" }
{ "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }
統計 php
集合中文檔的個數
db.集合名.count():返回集合中有多少個文檔
五、用戶管理(權限控制)
1、權限概述
在 MongoDB
里面的用戶是屬於數據庫的,每個數據庫都有自己的管理員。管理員登錄后,只能操作所屬的數據庫。注意:在 admin
的數據庫中創建的用戶是超級管理員,登陸后可以操作任何的數據庫
2、創建用戶
(1) 選擇數據庫
use 數據庫的名稱
(2) 添加用戶
db.createUser(用戶名,密碼,是否只讀)
第三個參數"是否只讀"默認是 false
,創建的用戶可以執行讀寫,如果是 true
,則創建的用戶只能查詢,不能修改。
注意點:在創建用戶之前,必須先創建一個超級管理員
example:
> use admin
switched to db admin
> db.createUser({user:'user',
... pwd:'passwd',
... roles:[
... {role:'userAdminAnyDatabase', db:'admin'}
... ]
... })
Successfully added user: {
"user" : "user",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
3、驗證權限(用戶登錄)
在添加完成管理員之后,我們做如下操作:
(1) 如果你是安裝成windows服務的方式安裝的,則卸載服務,在安裝時添加一個 -auth
選項,auth
表示要開啟權限認證
(2) 如果你是直接啟動的方式,則停止服務,重新啟動,在啟動時也要添加 --auth
選項,auth
表示要開啟權限認證
如果沒有通過權限驗證,直接操作數據庫,則報如下錯誤提示:
error: {
"$err" : "unauthorized db:test lock type:-1 client:127.0.0.1",
"code" : 10057
}
如何通過權限驗證
-
選擇數據庫
-
執行
db.auth
(用戶名,密碼)
4、刪除用戶和修改密碼
注意:創建的用戶名和密碼是存儲在各自數據庫里面的 system.users
集合里面的。想要刪除用戶,則直接刪除 system.users
集合里面的文檔即可
5、總結說明
a) 非 admin
數據庫的用戶不能使用數據庫命令,比如 show dbs
等
(b) admin
數據庫中的用戶被視為超級用戶(即管理員),在認證之后,管理員可以讀寫所有數據庫,執行特定的管理命令。
(c) 在開啟安全檢查之前,一定要至少有個管理員賬戶。
(d) 數據庫的用戶賬號以文檔的形式存儲在 system.users
集合里面。可以在 system.users
集合中刪除用戶賬號文檔,就可以刪除用戶。
六、MongoDB中的索引
1、普通單列索引
我們用如下代碼來測試:
for(var i=0;i<200000;i++){
db.java.insert({name:'xiao'+i,age:i})
}
第一、我們先檢驗一下查詢性能
var start=new Date()
db.java.find({name:'xiao156789'})
var end=new Date()
end-start
17510
第二、為 name
創建索引
> db.java.ensureIndex({name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
第三、再執行第一部分代碼可以看出有數量級的性能提升
語法:db.集合名.ensureIndex({鍵名:1})
:1是升序,-1是降序
2、多列索引(復合索引)
創建多列索引
語法:db.集合名.ensureIndex({field1:1/-1,field2:1/-1})
對 name
和 age
建立一個復合索引,可以使用 db.集合名.getIndexes()
查看創建的索引情況
3、子文檔索引
語法: db.集合名.ensureIndex({field.subfield:1/-1})
如下文檔可以建立子文檔索引
{name:'諾基亞手機1',price:12.34,spc:{weight:100,area:'紐約'}}
{name:'諾基亞手機2',price:42.34,spc:{weight:200,area:'倫敦'}}
比如要查詢 weight=100
的文檔
db.goods.find({'spc.weight':100})
根據當前案例,我們建立子文檔索引
db.net.ensureIndex({'spc.w':1})
4、唯一索引
語法: db.集合名.ensureIndex({name:-1},{unique:true})
5、查看索引
(1) 查看當前索引狀態: db.集合名.getIndexes()
(2) 詳情查看本次查詢使用哪個索引和查詢數據的狀態信息: db.集合名.find({name:''xiao}).explain()
6、刪除索引
刪除單個索引: db.集合名.dropIndex({filed:1/-1})
刪除所有索引: db.集合名.dropIndexes()
7、重建索引
一個表經過很多次修改后,導致表的文件產生空洞,索引文件也如此,可以通過索引的重建,減少索引文件碎片,並提高索引的效率,類似 mysql
中的 optimize table
。
mysql
里面使用 optimize table
語法: optimize table
表名
語法: db.集合名.reIndex()
8、索引使用注意事項
(1) 創建索引的時候,注意1是正序創建索引,-1是倒序創建索引
(2) 索引的創建在提高查詢性能的同時會影響插入性能,對於經常查詢少插入
(3) 復合索引要注意索引的先后順序
(4) 每個鍵全建立索引不一定就能提高性能,索引不是萬能的。
(5) 在做排序工作的時候如果是超大數據量也可以考慮加上索引用來提高排序的性能。
八、MongoDB中的數據導出與導出
利用mongoexport
-
-h host主機
-
-port 端口
-
-d 指明使用的庫
-
-o 指明要導出的文件名
-
-csv 指定導出的csv格式
-
-q 過濾導出
-
-f field1 field2 列名
-
-u username 用戶名
-
-p password 密碼
注意:在使用用戶名和密碼是超級管理員的時候,如果端口是默認的可以不使用-port來指定端口
(2) 導入數據
-
-d 待導入的數據庫
-
-c 待導入的集合(不存在會自己創建)
-
-type csv/json(默認)
-
-file 備份文件路徑
例如:導入json
./bin/mongoimport -h -port 端口號 -d test -c goods -file ./goodsall.json
導入csv
./bin/mongoimport -h -port 端口號 -d test -c goods -type csv -f goods.id,goods.name -file ./goodsall.csv
./bin/mongoimport -h -port 端口號 -d test -c goods -type csv -f -headline -f goods.id,goods.name -file ./goodsall.csv
九、主從復制(讀寫分離)
主從復制是一個簡單的數據庫同步備份的集群技術,至少兩台數據庫服務器,可以分別設置主服務器和從服務器,對主服務器的任何操作都會同步到從服務器上。
實現的注意點
1、在數據庫集群中要明確的知道誰是主服務器,主服務器只有一台
2、從服務器要知道自己的數據源 也就是對應的主服務是誰
3、--master用來確定主服務器 --slave和--source來控制從服務器
配置步驟
(1) 啟動主服務器
(2) 啟動從服務器
(3) 客戶端登錄到主服務器
添加一些數據,測試是否同步到從服務器,在主服務器里面,添加了一些文檔:
第一步,客戶端登錄到主服務器,添加一些文檔
第二步,登錄到從服務器,查看是否有數據,如果有數據,則成功了!
十、php操作MongoDB
1、安裝擴展
注意:擴展文件,下載合適的php_mongodb.dll文件
-
php的版本
-
是否是線程安全的thread safe(ts)
-
是vc幾的
-
php是32位的還是64位的
步驟
-
把對應的擴展,拷貝到PHP的安裝目錄里面的ext目錄下面,注意:拷貝后改名為php_mongo.dll,方便管理
-
打開php.ini文件,引入該擴展
extension=php_mongo.dll
- 重啟Apache,使用phpinfo()函數測試
2、入門使用
- 連接mongodb服務器
$m=new MongoClient("mongodb://root:root@localhost:8888/admin");
$db=$m->selectDb("stu");//選擇數據庫
- 增刪改查用法
增刪改查
注意,在命令行里面的"." 變成了"->","{}"變成了數組
a) 添加一個文檔
$db->php->insert(array('name'=>'李元霸','age'=>12));
b) 查詢文檔
$data=$db->php->find();
查詢年齡等於9的文檔:
$data=$db->php->find(array('age'=>9));
查詢年齡大於9的文檔:
//db.php.find({age:{'$gt':9}})
$data=$db->php->find(array('age'=>array('$gt':9)));
根據年齡降序顯示:
$data=$db->php->find()->sort(array('age'=>1));
foreach($data as $v){
echo $v['name'].'----'.$v['age'].'--'.$v['email'].'';
}
c) 修改文檔,我們直接使用修改器來完成
把年齡等於8的名稱改名為李白:
//db.php.update({age:8},{'$set':{'name':'李白'}})
$db->php->update(array('age'=>8),array('$set'=>array('name'=>'李白'));
d) 刪除文檔
比如刪除年齡等於10的文檔:
//db.php.remove({age:10})
$db->php->remove(array('age'=>10))
$data=$db->php->find()
foreach($data as $v){
echo $v['name'].'----'.$v['age'].'--'.$v['email'].'';
}
- 把mysql表里面的數據存儲到mongodb里面
selectDb("stu");//選擇數據庫
//從mysql里面取出數據
$conn=mysql_connect('localhost','root','root');
mysql_query('use shop');
mysql_query('set names utf8');
$sql="select * from goods";
$res=mysql_query($sql);
while($row=mysql_fetch_assoc($res)){
$db->goods->insert($row);
}
echo 'ok';