一、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
数据库中的用户被视为超级用户(即管理员),在认证之后,管理员可以读写所有数据库,执行特定的管理命令。
© 在开启安全检查之前,一定要至少有个管理员账户。
(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';