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) + '\n') ## str()寫可以寫入文件,但是寫到文件中的每條數據不是json格式,而是字符串格式,json.dumps()寫入的是json格式文件,也只有json格式文件才可用MONGODB客戶端導入數據庫。
                f.write(json.dumps(data,ensure_ascii=False) + '\n')  ## 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
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM