在python中,连接并操作mongo主要使用了pymongo库。
3.6版本的mongo安装后需要创建/data/db文件夹,并设置其权限或改变拥有者。通过nohup mongod &方式可以将mongo以后台服务方式启动。
说明:本文中的mongo为单节点环境,集群环境见:mongo集群。
先安装mongo(见参考资料1),并创建一个库:mytest,collection为person,插入一条记录:_id:1。连接并查询:
import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)
db = client.mytest
collection = db.person
result = collection.find_one()
print result
输出结果如下:
{u'_id':1.0}
首先,要连接上mongoDB,通过pymongo库里的MongoClient来实现。传入host和port两个参数,或者直接传入一个连接字符串也行,如下所示:
client = MongoClient('mongodb://localhost:27017/')
然后,获取到db和collection。client.mytest和client[‘mytest’]这两种方式是一样的效果。同样地,指定操作集合时,db.person和db[‘person’]也是一样的。
当collection中存在数据时,可通过collection的find()或find_one()方法来查询结果,其中find_one()查询得到的是单个结果,而find()则返回一个生成器对象。
现在往collection中插入数据。
import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)
db = client.mytest
collection = db.person
person = { "name": "Mike"}
collection.insert(person)
cur = collection.find()
for c in cur:
print c
输出结果如下:
{u'_id':1.0}
{u'_id': ObjectId('5cd8e716fcc8c12d8ee405ce'), u'name': u'Mike'}
第一条数据是从外面插入的,指定了_id为1。此处插入name为Mike的这条数据,由系统自动生成了ObjectId(当你创建文档时,可以通过给_id键赋值来覆写自动创建的ObjectID值)。
在Mongo3.x版本中官方已经不推荐使用insert()方法,而是替换成了insert_one()和insert_many(),用于插入单条记录和多条记录。
insert方法返回的结果是标识id(_id)列表,而insert_one方法返回的是一个InsertOneResult对象,通过inserted_id属性获取_id。
find()方法返回一个生成器对象,需要进行遍历才能得到对应的dict对象。而find_one()方法直接返回的就是一个dict对象。
import pymongo
client = pymongo.Mongo
Client(host='localhost', port=27017)
db = client.mytest
collection = db.person
curson = collection.find({"name": "Mike"})
print("curson type is %s" % type(curson))
for c in curson:
print("c type is %s " % type(c))
print c
结果如下:
curson type is
c type is
{u'_id': ObjectId('5cd8e716fcc8c12d8ee405ce'), u'name': u'Mike'}
除了字符串精确匹配查询之外,对于整形,支持以下操作:
符号 | 含义 | 示例 |
---|---|---|
$lt,$gt | 小于, 大于 | {‘age’: {’$lt’: 20}} |
$lte, $gte | 小于等于,大于等于 | {‘age’: {’$lte’: 20}} |
$ne | 不等于 | {‘age’: {’$ne’: 20}} |
$in | 在范围内 | {‘age’: {’$in’: [20, 23]}} |
$nin | 不在范围内 | {‘age’: {’$nin’: [20, 23]}} |
还有其他一些高级的用法如下所示:
符号 | 含义 | 示例 | 说明 |
---|---|---|---|
$regex | 正则匹配 | {‘name’: {’$regex’: ‘^M.*’}} | |
$exists | 属性是否存在 | {‘name’: {’$exists’: True}} | |
$type | 类型判断 | {‘age’: {’$type’: ‘int’}} | age的类型为int |
$mod | 数字模操作 | {‘age’: {’$mod’: [5, 0]}} | 年龄模5余0 |
$text | 文本查询 | {’$text’:{’$search’: ‘Mike’}} | text类型的属性中包含Mike字符串 |
$where | 高级条件查询 | {’$where’: ‘obj.fans_count == obj.follows_count’} | 自身粉丝数等于关注数 |
分组聚合
db.xx.aggregate([{$group:{_id:’$name’, count:{$sum:1}}}])
计数直接调用count函数:
count = collection.find().count()
或count = collection.find({'name':'Mike'}).count()
排序直接调用sort函数:
results = collection.find().sort('name', pymongo.ASCENDING)
,降序为pymongo.DESCENDING
偏移直接调用skip函数:
results = collection.find().sort('name', pymongo.ASCENDING).skip(2)
限制查询结果数直接调用limit函数:
results = collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2)
使用update()进行数据更新:
condition = {'name': 'Mike'}
student = collection.find_one(condition)
student['age'] = 25
result = collection.update(condition, student)
print result
运行结果如下:
{'ok': 1, 'nModified': 1, 'n': 1, 'updatedExisting': True}
返回字典形式结果, ok表示执行成功,nModified表示影响条数。
也可以使用$set操作符对数据进行更新,如下所示:
result = collection.update(condition, {'$set': student})
是否使用$set的区别在于:
不使用$set时,会使用当前更新的字典对象替换原对象,新对象中不含而旧对象中存在的字段会消失。
使用$set时,则只更新新对象中存在的字段,旧对象的其他字段保持不变。
实际上,update也是官方不推荐使用的方法,推荐的是update_one和update_many,它们的第二个参数必须使用$set作为字典的键名,不允许直接传入修改后的新字典对象。
result = collection.update_one({"name": "Mike"}, {"$set": {"name": "Tom"}})
print result, result.matched_count, result.modified_count
cur = collection.find()
for r in cur:
print r
update_one和update_many方法返回的结果是一个UpdateResult,其中matched_count属性和modified_count属性分别表示匹配的数据条数和影响的数据条数。
update_many会更新所有符合条件的数据。
update_many可以更新符合条件的多条数据,这是一种意义上的批量更新。还有另外一种批量更新,指的是将多次更新操作一起执行,如下所示:
op1 = pymongo.UpdateOne({"name": "Mike"}, {"$set": {"name": "Tom"}})
op2 = pymongo.UpdateOne({"name": "Jack"}, {"$set": {"name":"Hanse"}})
update_operations.append(op1)
update_operations.append(op2)
collection.bulk_write(ops)
批量更新时有个坑要注意下,bulk_write函数实际上有三个参数,后两个参数意义分别是:执行操作的有序性和是否验证文档规则约束。根据需要进行指定,而不指定的情况下分别为True和False。当在认证登录的情况下,如果将后一个参数指定为True,则此更新操作会报权限错误。
删除操作通过remove函数来进行,在参数中指定删除条件:
result = collection.remove({"name": "Mike"})
remove返回结果是一个dict对象:
{'ok': 1, 'n': 1}
表示执行成功,删除条数为1。
同样地,官方推荐方法为delete_one()和delete_many(),返回结果是DeleteResult对象,其中的deleted_count属性为删除的数据条数。
其他还有一些组合操作,如find_one_and_delete(),finde_one_and_replace,find_one_and_update。
通过
use admin;
db.createUser({user:"root", pwd:"root", roles:[{"role":"dbAdminAnyDatabase", "db":"admin"},{"role":"userAdminAnyDatabase","db":"admin"}]})
来添加用户。
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以指定数据库里创建、删除和管理用户
root:只在admin数据库中可用。超级账号,超级权限
开启服务时通过–auth来开启验证:
nohup mongod --auth &
通过
mongo -uroot -proot -authenticationDatabase admin
进行登录。登录后切换到admin库(默认是test库),通过命令show users可以查看admin库添加的用户。
但切换到mytest库后仍然不具有访问权限。添加mytest库用户:
use mytest
db.createUser({user:"root", pwd:"root", roles:[{"role":"readWrite","db":"mytest"}]})
readWrite:允许用户读写指定数据库
重新认证登录:
mongo -uroot -proot -authenticationDatabase mytest
切换到mytest之后访问person集合:
use mytest
db.person.find()
当前登录用户对mytest库具有读写权限,因此可以访问集合。
[1]https://www.jianshu.com/p/430ef6441601
[2]https://juejin.im/post/5addbd0e518825671f2f62ee
[3]https://docs.mongodb.com/manual/reference/operator/query/
[4]https://blog.csdn.net/uevol14/article/details/53885779