mongo数组操作(增、删、改、查)python

    技术2022-07-13  85

    连接数据库

    pythonmongopymongo3.6.53.4.10 Community3.7.2 import pymongo class MongoStore(object): def __init__(self): try: self._server_client = pymongo.MongoClient(Config.SERVER_MONGOURL, connect=False) self._server_db = self._server_client.get_database(Config.CASICFUND_TOUYAN_MONGO_DB) self._news_db = self._server_client.get_database(Config.NEWS_MONGO_DB) except Exception as e: log.commit_err(f"connecnt to mongo error, MONGOURL={Config.SERVER_MONGOURL}") raise DBConnectError def ping(self): self.user_collection().find_one() def test_conn(self): return self._server_db.get_collection("test") ServerMongoStore = MongoStore() ServerMongoStore.ping()

    数据库操作

    1. 增

    1.1 插入到数组尾部

    { $push: {<字段名1>: <值1>, <字段名2>: <值2>, … } }

    $push将给定数值(<值1>)插入到目标数组(<字段名1>)中,操作对象必须为数组类型的字段。如果记录中不存在指定的字段名,将指定的字段名以数组对象的形式推入到记录中并填充其指定的数值;如果记录中存在指定的字段名,且字段名存在指定的数值,指定的数值也会被推入到记录中。

    def test1(): conn = ServerMongoStore.test_conn() for i in range(10): conn.update_one({"name": "test1"}, {"$push": { "locs": {"name": str(i), "create_time": randint(0, 100)}}}, True) item = conn.find_one({"name": "test1"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果:

    [{'name': '0', 'create_time': 70}, {'name': '1', 'create_time': 5}, {'name': '2', 'create_time': 79}, {'name': '3', 'create_time': 5}, {'name': '4', 'create_time': 34}, {'name': '5', 'create_time': 70}, {'name': '6', 'create_time': 55}, {'name': '7', 'create_time': 70}, {'name': '8', 'create_time': 44}, {'name': '9', 'create_time': 13}]
    1.2 插入数组,并让数组按照某种方法排序

    会根据create_time 增序的对数据进行排序。一般来说,向数组尾部插入的效率会更高。

    def test2(): conn = ServerMongoStore.test_conn() for i in range(10): conn.update_one({"name": "test2"}, {"$push": { "locs": {"$each": [{"name": str(i), "create_time": randint(0, 100)}], "$sort": {"create_time": 1}}}}, True) item = conn.find_one({"name": "test2"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果:

    [{'name': '8', 'create_time': 3}, {'name': '3', 'create_time': 27}, {'name': '9', 'create_time': 37}, {'name': '5', 'create_time': 44}, {'name': '0', 'create_time': 49}, {'name': '4', 'create_time': 49}, {'name': '1', 'create_time': 57}, {'name': '6', 'create_time': 73}, {'name': '7', 'create_time': 85}, {'name': '2', 'create_time': 99}]
    1.3 插入数组,并让数组按照某种方法排序。只保留5条数据
    def test3(): conn = ServerMongoStore.test_conn() for i in range(10): conn.update_one({"name": "test3"}, {"$push": { "locs": {"$each": [{"name": str(i), "create_time": randint(0, 100)}],"$slice": -5, "$sort": {"create_time": 1}}}}, True) item = conn.find_one({"name": "test3"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果

    [{'name': '4', 'create_time': 72}, {'name': '7', 'create_time': 72}, {'name': '1', 'create_time': 85}, {'name': '9', 'create_time': 87}, {'name': '8', 'create_time': 100}]
    1.4 将数组作为集合,只插入非重复数据

    { $addtoset: { <字段名1>: [ <值1>,<值2>,…,<值N>] ,<字段名2>: [ <值1>,<值2>,…,<值N> ], … } }

    $addtoset是向数组对象中添加元素和值,操作对象必须为数组类型的字段

    def test4(): conn = ServerMongoStore.test_conn() for i in range(100): conn.update_one({"name": "test4"}, {"$addToSet": { "locs": randint(0, 5)}}, True) item = conn.find_one({"name": "test4"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果:

    [3, 5, 0, 2, 1, 4]
    1.5 将数组作为集合,只插入非重复数据。一次插入多个
    def test5(): conn = ServerMongoStore.test_conn() updates = [] for i in range(1000): updates.append(randint(0,5)) conn.update_one({"name": "test5"}, {"$addToSet": { "locs": {"$each":updates}}}, True) item = conn.find_one({"name": "test5"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果

    [1, 2, 0, 4, 3, 5]
    1.6 将数组中的数据全部插入到数组中

    { $push_all: {<字段名1>:[<值1>,<值2>,…,<值N>], <字段名2>: [<值1>,<值2>,…,<值N>], … } }

    $push_all向指定数组对象(如<字段名1>)推入每一个指定值([<值1>,<值2>,…,<值N>])。操作对象必须为数组类型的字段。如果记录中不存在指定的数组对象,向记录推入指定的数组对象和每一个指定的值([<值1>,<值2>,…,<值N>]);如果指定的值存在数组对象中,同样被推入到数组对象中。

    def test6(): conn = ServerMongoStore.test_conn() updates = [] for i in range(10): updates.append({"name": str(i), "create_time": randint(0, 100)}) conn.update_one({"name": "test6"}, {"$pushAll": { "locs": updates}}, True) item = conn.find_one({"name": "test6"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果

    [{'name': '0', 'create_time': 41}, {'name': '1', 'create_time': 73}, {'name': '2', 'create_time': 15}, {'name': '3', 'create_time': 67}, {'name': '4', 'create_time': 7}, {'name': '5', 'create_time': 22}, {'name': '6', 'create_time': 12}, {'name': '7', 'create_time': 6}, {'name': '8', 'create_time': 48}, {'name': '9', 'create_time': 33}]

    2.删

    2.1 从数组头部或尾部删除一个数据

    { $pop: { <字段名1>: <值1>, <字段名2>: <值2>, … } }

    $pop 操作是删除指定数组对象(<字段名1>,<字段名2>,…)尾部 N 个元素,N 的大小由“<值>"决定。如果记录中不存在指定的数组对象,则不做任何操作;如果 N 大于数组对象的长度,数组对象的长度更新为 0,即它的元素全部被删除;如果 N < 0,则从数组头部删除 N 个元素

    def test7(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test1"}, {"$pop":{"locs":1}}) item = conn.find_one({"name": "test1"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果

    [{'name': '0', 'create_time': 70}, {'name': '1', 'create_time': 5}, {'name': '2', 'create_time': 79}, {'name': '3', 'create_time': 5}, {'name': '4', 'create_time': 34}, {'name': '5', 'create_time': 70}, {'name': '6', 'create_time': 55}, {'name': '7', 'create_time': 70}, {'name': '8', 'create_time': 44}]
    2.2 删除数组中完全匹配的元素

    { $pull: { <字段名1>: <值1>, <字段名2>: <值2>, … } }

    $pull 要求操作的记录中 <字段名> 的值必须是数组,它从数组中删除与 <值> 相同的元素

    def test8(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test1"}, {"$pull":{"locs": {'name': '0', 'create_time': 70}}}) item = conn.find_one({"name": "test1"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果

    [{'name': '1', 'create_time': 5}, {'name': '2', 'create_time': 79}, {'name': '3', 'create_time': 5}, {'name': '4', 'create_time': 34}, {'name': '5', 'create_time': 70}, {'name': '6', 'create_time': 55}, {'name': '7', 'create_time': 70}, {'name': '8', 'create_time': 44}]
    2.3 删除数组中完全匹配的多个元素

    { $pull_all: { <字段名1>: [ <值1>, <值2>, …, <值N> ], <字段名2>: [ <值1>, <值2>, …, <值N> ], … } }

    $pull_all 与 p u l l 功 能 类 似 。 区 别 在 于 : pull 功能类似。区别在于: pullpull 只能匹配某个字段的一个值,$pull_all 能匹配某个字段的多个值。

    def test9(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test1"}, {"$pullAll":{"locs": [{'name': '1', 'create_time': 5}, {'name': '2', 'create_time': 79}, {'name': '3', 'create_time': 5}, {'name': '4', 'create_time': 34}]}}) item = conn.find_one({"name": "test1"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果:

    [{'name': '5', 'create_time': 70}, {'name': '6', 'create_time': 55}, {'name': '7', 'create_time': 70}, {'name': '8', 'create_time': 44}]
    2.4 数组中元素为对象时,通过对象中的键删除元素

    { $pull_by: { <字段名1>: <值1>, <字段名2>: <值2>, … } }

    $pull_by 与 $pull 功能类似。

    区别在于:

    $pull_by 若 <值> 为对象时,只要 <值> 中的所有字段值与数组元素的字段值相同,则认为匹配成功,并删除数组中的元素。

    $pull 若 <值> 为对象时,需要数组元素的每个字段值都与 <值> 中的字段值相同,才认为匹配成功,并删除数组中的元素。

    在python中 $pull 操作符同样支持 $pull_by 操作

    def test10(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test1"}, {"$pull":{"locs": {"create_time": {"$gt": 0}}}}) item = conn.find_one({"name": "test1"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs"))

    结果:

    []

    3. 改

    3.1 基于位置进行修改
    def test12(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test3"}, {"$inc": {"locs.0.create_time": 1}}) item = conn.find_one({"name": "test3"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs")[0])

    结果

    {'name': '4', 'create_time': 83}
    3.2 通过定位操作定位要修改的元素

    很多情况下,并不知道要修改数组中哪个元素,可以使用“$”来定位要修改的元素。但要注意,定位操作只能定位到匹配的第一个元素

    def test13(): conn = ServerMongoStore.test_conn() conn.update_one({"name": "test3", "locs.create_time":{"$gt":0}}, {"$inc": {"locs.$.create_time": 1}}) item = conn.find_one({"name": "test3"}, {"locs": 1, "_id": 0}) if item: print(item.get("locs")[:2])

    结果

    [{'name': '4', 'create_time': 86}, {'name': '7', 'create_time': 72}]

    4 查

    4.1 通过数组中的某个元素,匹配数组

    查询条件匹配到了数组中的某个元素, 返回整个文档

    def test14(): conn = ServerMongoStore.test_conn() item = conn.find_one({"locs": {"name": "4","create_time": 86}}) if item: print(item.get("name"))

    结果

    test3
    4.2 匹配数组中的全部元素才返回文档
    def test15(): conn = ServerMongoStore.test_conn() item = conn.find_one({"locs": {"$all":[{'name': '4', 'create_time': 86}, {'name': '7', 'create_time': 72}, {'name': '1', 'create_time': 85}, {'name': '9', 'create_time': 87}, {'name': '8', 'create_time': 100}] }}) if item: print(item.get("name"))

    结果

    test3
    4.3 匹配数组长度
    def test16(): conn = ServerMongoStore.test_conn() item = conn.find_one({"locs": {"$size": 5}}) if item: print(item.get("name"))

    结果

    test3
    4.4 返回匹配数组的部分字段
    def test16(): conn = ServerMongoStore.test_conn() item = conn.find_one({"name":"test3"},{"locs.create_time":1}) if item: print(item)

    结果

    {'_id': ObjectId('5efd7ccd7bfc4296095cd6ea'), 'locs': [{'create_time': 86}, {'create_time': 72}, {'create_time': 85}, {'create_time': 87}, {'create_time': 100}]}
    4.5 返回数组部分长度
    def test17(): conn = ServerMongoStore.test_conn() item = conn.find_one({"name":"test3"},{"locs":{"$slice": -2}}) if item: print(item)

    返回了数组尾部2个元素, 想返回开头则{“locs”:{"$slice": 2}}

    {'_id': ObjectId('5efd7ccd7bfc4296095cd6ea'), 'name': 'test3', 'locs': [{'name': '9', 'create_time': 87}, {'name': '8', 'create_time': 100}]}

    $slice 也支持数组

    def test17(): conn = ServerMongoStore.test_conn() item = conn.find_one({"name":"test3"},{"locs":{"$slice": [1,3]}}) if item: print(item)

    结果是数组首尾都包含的

    {'_id': ObjectId('5efd7ccd7bfc4296095cd6ea'), 'name': 'test3', 'locs': [{'name': '7', 'create_time': 72}, {'name': '1', 'create_time': 85}, {'name': '9', 'create_time': 87}]}
    Processed: 0.013, SQL: 9