• python操作MONGODB数据库,提取部分数据再存储


    目标:从一个数据库中提取几个集合中的部分数据,组合起来一共一万条。几个集合,不足一千条数据的集合就全部提取,够一千条的就用一万减去不足一千的,再除以大于一千的集合个数,得到的值即为所需提取文档的个数。从每个集合中提取的数据存放到新的对应集合中,新集合名称为原先集合加"_col"。

    用到相关技术点:

    操作MONGODB:

    先通过IP和端口号连接到MONGODB所在的机器,得到一个MONGODB客户端对象,然后认证某个数据库的账号密码连接到该数据库,得到一个该数据库的对象。一个数据库下有很多集合(相当于SQL中的表),集合里数据存储格式是BSON(同JSON)格式,集合中有很多条文档(相当于SQL中的记录)。可以通过数据库对象得到一个集合的对象,通过集合的对象来进行数据库增删改查的操作。

    MONGODB操作的函数:

    创建数据库:mydb = myclient["runoobdb"]

    查看该客户端的所有数据库:dblist = myclient.list_database_names()

    判断数据库是否存在:if "runoobdb" in dblist: print("数据库已存在!")

    创建集合:mycol = mydb["sites"]

    查看该数据库的所有集合:collist = mydb. list_collection_names()

    判断集合是否存在:if "sites" in collist:  print("集合已存在!")

    插入一个文档:

      mydict = { "name": "RUNOOB", "alexa": "10000", "url": "https://www.runoob.com" }

      x = mycol.insert_one(mydict)

      print(x)

      输出结果:<pymongo.results.InsertOneResult object at 0x10a34b288>

      insert_one() 方法返回 InsertOneResult 对象,该对象包含 inserted_id 属性,它是插入文档的 id 值。print(x.inserted_id)。如果我们在插入文档时没有指定 _id,MongoDB 会为每个文档添加一个唯一的 id

    插入多个文档:

      mylist = [ { "name": "Taobao", "alexa": "100", "url": "https://www.taobao.com" }, { "name": "QQ", "alexa": "101", "url": "https://www.qq.com" }, { "name": "Facebook", "alexa": "10", "url": "https://www.facebook.com" }, { "name": "知乎", "alexa": "103", "url": "https://www.zhihu.com" }, { "name": "Github", "alexa": "109", "url": "https://www.github.com" } ]

      x = mycol.insert_many(mylist)

      # 输出插入的所有文档对应的 _id 值

      print(x.inserted_ids)

    插入查询结果文档集:

      x.insert_many(mycol.find())

    查询一条数据:

      x = mycol.find_one() print(x)

    查询集合中所有数据:

      for x in mycol.find():

        print(x)

    查询指定字段:

      for x in mycol.find({},{ "_id": 0, "name": 1, "alexa": 1 }):  ##0表示该字段不出现,1表示该字段出现。除了_id字段,其他字段数字要一致,即要么都为0要么都为1。

        print(x)

    条件查询:

      等值查询:

        myquery = { "name": "RUNOOB" }

        mydoc = mycol.find(myquery)

        for x in mydoc:

          print(x)

      非等值查询:   

        # (>) 大于 - $gt
        # (<) 小于 - $lt
        # (>=) 大于等于 - $gte
        # (<= ) 小于等于 - $lte
        #例:查询集合中age大于25的所有记录
        for i in my_col.find({"age":{"$gt":25}}):
          print(i)

    正则表达式查询:

      ## 读取 name 字段中第一个字母为 "R" 的数据

      yquery = { "name": { "$regex": "^R" } }

      mydoc = mycol.find(myquery)

      for x in mydoc:

        print(x)

    查询指定条数记录:

      ## 返回 3 条文档记录

      myresult = mycol.find().limit(3)

      # 输出结果

      for x in myresult:

        print(x)

    查询结果集中第n条记录,及第n条记录某个字段的值:

      ## 查询按照alexa字段倒排后,第三条记录的alexa字段的值

      condition = col.find().sort("alexa",-1)[3]["alexa"]

      print(condition)

    查询一个集合中总文档个数:

      num_document = mycol.count_documents({})
      print(num_document)

    按照字段类型条件查找:

      #找出name的类型是String的
      for i in my_set.find({'name':{'$type':2}}):
        print(i)

      ‘’‘类型对照列表'''

      Double 1 

      String 2
      Object 3
      Array 4
      Binary data 5
      Undefined 6 已废弃
      Object id 7
      Boolean 8
      Date 9
      Null 10
      Regular Expression 11
      JavaScript 13
      Symbol 14
      JavaScript (with scope) 15
      32-bit integer 16
      Timestamp 17
      64-bit integer 18
      Min key 255 Query with -1.
      Max key 127

    limit和skip:

      #limit()方法用来读取指定数量的数据
      #skip()方法用来跳过指定数量的数据
      #下面表示跳过两条数据后读取6条
      for i in my_set.find().skip(2).limit(6):
        print(i)

    IN:

      #找出age是20、30、35的数据
      for i in my_set.find({"age":{"$in":(20,30,35)}}):
        print(i)

    OR:

      #找出age是20或35的记录
      for i in my_set.find({"$or":[{"age":20},{"age":35}]}):
        print(i)

    多级路径元素查找:

      ## 先插入一条数据 

      dic = {"name":"zhangsan",
        "age":18,
        "contact" : {
          "email" : "1234567@qq.com",
          "iphone" : "11223344"}
        }
      my_set.insert(dic)

      #多级目录用. 连接

      for i in my_set.find({"contact.iphone":"11223344"}):
        print(i)
      #输出:{'name': 'zhangsan', '_id': ObjectId('58c4f99c4fc9d42e0022c3b6'), 'age': 18, 'contact': {'email': '1234567@qq.com', 'iphone': '11223344'}}

     排序:

      ## sort() 方法第一个参数为要排序的字段,第二个字段指定排序规则,1 为升序,-1 为降序,默认为升序。

      ## 对字段 alexa 按降序排序

      mydoc = mycol.find().sort("alexa",-1)

      for x in mydoc:

        print(x)

    删除一个文档:

      ## delete_one() 方法来删除一个文档,该方法第一个参数为查询对象,指定要删除哪些数据。

      ## 删除 name 字段值为 "Taobao" 的文档

      myquery = { "name": "Taobao" }

      mycol.delete_one(myquery)

      # 删除后输出

      for x in mycol.find():

        print(x)

    删除多个文档:

      myquery = { "name": {"$regex": "^F"} }

      x = mycol.delete_many(myquery)

      print(x.deleted_count, "个文档已删除")

    删除集合中所有文档:

       ## delete_many() 方法如果传入的是一个空的查询对象,则会删除集合中的所有文档

      x = mycol.delete_many({})

      print(x.deleted_count, "个文档已删除")

    删除集合:

      mycol = mydb["sites"]

      mycol.drop()  ## 如果删除成功 drop() 返回 true,如果删除失败(集合不存在)则返回 false

    修改一条记录:

      ## update_one() 方法修改文档中的记录。该方法第一个参数为查询的条件,第二个参数为要修改的字段。如果查找到的匹配数据多余一条,则只会修改第一条。

      myquery = { "alexa": "10000" }

      newvalues = { "$set": { "alexa": "12345" } }

      mycol.update_one(myquery, newvalues)

      # 输出修改后的 "sites" 集合

      for x in mycol.find():

        print(x)

    修改多条记录:

      ## 将查找所有以 F 开头的 name 字段,并将匹配到所有记录的 alexa 字段修改为 123

      myquery = { "name": { "$regex": "^F" } }

      newvalues = { "$set": { "alexa": "123" } }
      x = mycol.update_many(myquery, newvalues)
      print(x.modified_count, "文档已修改")

      config.py

    ## 数据库URL
    MONGO_URL = 'mongodb://123.456.789.123:27017/'
    ## 数据库名称
    MONGO_DB = 'hellodb'

    mongodb_extract.py
    #导入存储MONGODB数据库的配置信息
    from config import *
    import pymongo

    ## 定义一个mongodb客户端
    client = pymongo.MongoClient(MONGO_URL)
    ## 连接数据库,账号密码认证
    db = client[MONGO_DB]
    db.authenticate("username", "password")

    '''问题:此函数得到的平均数,可能有的集合文档数目达不到。或者说可以按照每个集合比例数目提取数据'''
    def average_num():
    '''返回一个不大于1000个文档的集合,所需提取文档的个数列表。使得所要提取的几个集合所有提取文档个数为10000。'''
    ## 所有不大于1000的集合中的文档个数之和
    count = 0
    ## 不大于1000的集合个数
    i = 0
    ## 大于1000的集合所需提取文档的个数的列表
    extract_num = []
    for collection in db.list_collection_names():
    if "_col" not in collection:
    col = db[collection]
    num_document = col.count_documents({})
    print(num_document)
    if num_document <= 1000:
    count += num_document
    else:
    i += 1
    ## (10000-所有<1000的集合的文档之和)/大于1000的集合个数,取整数
    average = int((10000 - count) / i)
    ## (10000-所有<1000的集合的文档之和)% 大于1000的集合个数,求余
    remainder = (10000 - count) % i
    for j in range(i-1):
    extract_num.append(average)
    extract_num.append(average + remainder)
    return extract_num

    def extract_data():
    '''取出所有数据'''
    extract_num_list = average_num()
    for collection in db.list_collection_names():
    ## 几个集合的名称,每个类一个集合
    col = db[collection]
    ## 每个集合的文档个数
    num_document = col.count_documents({})
    if num_document <= 1000:
    ## 如果一个集合中文档数量不超过1000,全部提取存储
    db[collection + "_col"].insert_many(col.find({},{"infoId":0,"update_author":0,"Customs":0,"Customs_branch":0}))
    else:
    ## 如果集合文档大于1000,则提取根据日期排序最新的指定个数文档
    ## 指定数量文档为止的约束日期
    condition = col.find().sort("report_time",-1)[extract_num_list.pop()]["report_time"]
    ## 将大于约束日期的数据提取并存储
    db[collection + "_col"].insert_many(col.find({"report_time":{"$gte":condition}},{"infoId":0,"update_author":0,"Customs":0,"Customs_branch":0}))

    def main():
    extract_data()

    if __name__ == '__main__':
    main()
    write_data.py
    '''将提取后的数据集合分别写到对应的.json文件中'''
    #导入存储MONGODB数据库的配置信息
    from config import *
    import pymongo
    import json

    ## 定义一个mongodb客户端
    client = pymongo.MongoClient(MONGO_URL)
    ## 连接数据库,账号密码认证
    db = client[MONGO_DB]
    db.authenticate("username", "password")


    for collection in db.list_collection_names():
    if "_col" in collection:
    col = db[collection]
    with open(collection[:-4] + '.json', 'a', encoding='utf-8') as f:  ## a表示文件可追加,编码utf-8防止中文乱码
    for data in col.find():
              #f.write(str(data) + ' ') ## str()写可以写入文件,但是写到文件中的每条数据不是json格式,而是字符串格式,json.dumps()写入的是json格式文件,也只有json格式文件才可用MONGODB客户端导入数据库。
                    f.write(json.dumps(data,ensure_ascii=False) + '
    ')  ## json.dumps()得到的数据默认是ascii编码,这里ensure_ascii=False不让它编码为ascii格式。
            f.close()

    参考:http://www.runoob.com/python3/python-mongodb.html
       https://www.cnblogs.com/melonjiang/p/6536876.html
     
  • 相关阅读:
    数据库设计
    最近发生的事
    轻松搞定面试中的二叉树题目
    二叉树的遍历方法
    静态库Lib和动态库Dll
    深入理解C/C++数组和指针
    夜间日记
    typedef用法小结
    什么是静态链接库,什么是动态链接库
    线段树
  • 原文地址:https://www.cnblogs.com/wisir/p/10682416.html
Copyright © 2020-2023  润新知