• MongoDB与Pymongo深度实践:从基础概念到无限级评论应用示例


    在这里插入图片描述



    前言

        随着数据量的爆炸性增长,高效的数据存储与管理成为关键。MongoDB,作为NoSQL数据库的佼佼者,凭借其灵活的文档模型、高可扩展性和强大的查询能力,赢得了广泛关注。本博客将深入浅出地介绍MongoDB的基本概念、核心操作及实际应用,从基础概念到Docker安装,再到pymongo的使用,最后通过无限级评论功能展示MongoDB在项目开发中的实际应用。

    在这里插入图片描述

    MongoDB官方文档:https://www.mongodb.com/zh-cn/docs/manual/


    一、MongoDB

    1.基本介绍

        MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。它介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

    关系型数据库(Relational Databases)

    • 代表产品: MySQL, SQLite, PostgreSQL
    • 主要功能:
      • 数据存储: 高效、安全地存储结构化数据。
      • 关系管理: 支持复杂的数据关系建模,包括一对一、一对多、多对多等关系。
      • 事务支持: 确保数据的一致性和完整性,通过事务控制来实现。
      • ACID特性: 具备原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)等特点。
    • 应用场景: 适合需要强数据一致性和复杂查询的企业级应用,如电商、金融系统等。

    NoSQL数据库(Non-Relational Databases)

    • 代表产品: Redis
    • 主要功能:
      • 高性能: 通过非关系型数据模型,提供极高的读写速度和吞吐量。
      • 灵活性: 支持多种数据类型,如键值对、文档、列族、图等,以适应不同的数据模型需求。
      • 可扩展性: 水平扩展能力强,轻松应对大规模数据增长。
    • 应用场景: 适用于对数据一致性要求不那么严格,但追求高性能和可扩展性的场景,如缓存、实时消息系统等。

    向量数据库(Vector Databases)

    • 代表产品: Elasticsearch (虽然通常被认为是搜索引擎,但也可用于向量搜索), FAISS
    • 主要功能:
      • 高级检索: 支持基于向量的相似性搜索,能够高效地在海量数据中查找相似的对象或内容。
      • 优化搜索: 通过向量索引和查询优化技术,实现快速且准确的搜索结果。
      • 灵活匹配: 适用于各种非文本内容的搜索,如图像、音频、视频等多媒体数据。
    • 应用场景: 适合需要复杂搜索功能的场景,如推荐系统、图像识别、自然语言处理等。

        关系型数据库提供强大的数据一致性和关系管理能力,适合结构化数据的处理;NoSQL数据库以其高性能和灵活性,成为处理大规模非结构化数据的理想选择;而向量数据库则通过高级检索功能,为需要复杂搜索功能的场景提供了解决方案。
        在实际应用中,还可以根据业务发展和数据量的变化,采用混合数据库架构,结合不同类型数据库的优势,以构建更加高效、灵活、可扩展的数据系统。

    2.概念解析

    SQL术语/概念MongoDB术语/概念解释/说明
    databasedatabase数据库
    tablecollection数据库表/集合
    rowdocument数据记录行/文档
    columnfield数据字段/域
    indexindex索引
    table joins表连接,MongoDB不支持
    primary keyprimary key主键,MongoDB自动将_id字段设置为主键

    3.常见的数据类型

    • Object ID: ⽂档ID
    • String: 字符串, 最常⽤, 必须是有效的UTF-8
    • Boolean: 存储⼀个布尔值, true或false
    • Integer: 整数可以是32位或64位, 这取决于服务器
    • Double: 存储浮点值
    • Arrays: 数组或列表, 多个值存储到⼀个键
    • Object: ⽤于嵌⼊式的⽂档, 即⼀个值为⼀个⽂档
    • Null: 存储Null值
    • Timestamp: 时间戳, 表示从1970-1-1到现在的总秒数
    • Date: 存储当前⽇期或时间的UNIX时间格式

    4.Docker 安装

    docker search mongo
    docker pull mongo
    #运行容器
    docker run -itd --name mongo -p 27017:27017 mongo --auth 
    #进入容器
    docker exec -it mongo mongosh admin
    #使用admin数据
    #创建用户
    db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});
    
    #配制权限
    db.auth('admin', '123456')
    

    5.常用命令

    # 进入mongo容器,使用上文创建的账号
    docker exec -it mongo mongosh --username admin --password 123456
    #查看已经存在的数据库
    show dbs;
    #创建数据库
    use 数据库名
    #删除数据库
    db.dropDatabase()
    #查看集合
    show collections;
    #创建集合
    db.createCollection("news")
    #删除集合
    db.runoob.drop()
    #添加数据
    db.集合名.insert({'id':1,'title':'12'})
    db.集合名.insert({'id':1,'title':'12','name':'sdfsd'})
    #查询所有
    db.集合名.find()
    #删除数据
    db.集合名.remove({"id":1})
    #条件查询
    db.集合名.find({"id":1})
    
    

    二、Pymongo

    1.基本操作(连接、数据库、集合)

    安装:pip install pymongo

    pymongo连接:

    import pymongo
    from urllib import parse
    username = parse.quote_plus('admin')   # 对用户名进行编码
    password = parse.quote_plus('123456')  # 对密码进行编码
    database = "admin" # 数据库名称
    host     = "123.123.123.123"
    port     = "27017"
    mongo = pymongo.MongoClient('mongodb://%s:%s@%s:%s/%s' % ( username, password, host, port, database))
    

    数据库操作:

    import pymongo
    
    # 数据库连接
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    
    # 创建数据库
    my_db  = mongo["my_db"] 
    
    # 查看数据库列表
    print(mongo.list_database_names()) # 上面的 my_db 因为没有内容,所以没有被创建的。
    

    集合操作:

    import pymongo
    
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    my_db = mongo["my_db"]
    
    my_collection = my_db["my_collection"] # 没有往集合里面保存文档之前,mongdb不会真正创建集合!
    
    # 查看集合列表
    print(my_db.list_collection_names())
    
    # 删除集合
    my_collection.drop() # 删除成功返回true,如果集合不存在,返回false
    

    2.基本操作(增删改查)

    添加:

    import pymongo
    
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    my_db = mongo["my_db"]
    my_collection = my_db["my_collection"]
    
    # 添加一个文档
    document = { "name": "xiaoming", "mobile": "13012345678","age":16}
    ret = my_collection.insert_one(document)
    print(ret.inserted_id) # 返回InsertOneResult对象
    # 插入文档时,如果没有指定_id,将自动分配一个唯一的id。
    
    # 添加多个文档
    document_list = [
     { "name": "xiaoming", "mobile": "13033345678","age":17},
     { "name": "xiaohong", "mobile": "13044345678","age":18},
     { "name": "xiaohei",  "mobile": "13612345678","age":18},
    ]
    ret = my_collection.insert_many(document_list)
    
    # 打印文档_id值列表:
    print(ret.inserted_ids)
    

    删除:

    import pymongo
    
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    my_db = mongo["my_db"]
    my_collection = my_db["my_collection"]
    
    # 删除一个文档
    query = {"name":"xiaoming"}
    my_collection.delete_one(query)
    
    # 删除多个文档
    query = { "mobile": {"$regex": "^130"} }
    ret = my_collection.delete_many(query)
    print("删除了%d个文档" % ret.deleted_count)
    
    import pymongo
    from urllib.parse import quote_plus
    
    from bson import ObjectId
    
    if __name__ == "__main__":
       username = quote_plus("mofang")
       password = quote_plus("123456")
       # 获取数据库连接对象
       mongo = pymongo.MongoClient(f"mongodb://{username}:{password}@127.0.0.1:27017/mofang")
       mofang = mongo["mofang"]
       user_list = mofang["user_list"]
    
       """删除文档"""
       query = {"_id": ObjectId("60d925e127bd4b7769251002")}
       ret = user_list.delete_one(query)
       print(ret)
       print(ret.deleted_count)
       """删除多个文档"""
       query = {"name": "xiaolan"}
       ret = user_list.delete_many(query)
       print(ret.deleted_count)
    

    更新:

    import pymongo
    
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    my_db = mongo["my_db"]
    my_collection = my_db["my_collection"]
    
    # 更新一个文档
    query = { "name": "xiaoming" }
    data = { "$set": { "age": 18 } }
    my_collection.update_one(query, data)
    
    # 更新所有文档
    query = { "mobile": {"$regex": "^130"} }
    data = { "$set": { "age": 18 } }
    my_collection.update_many(query, data)
    

    查询:

    import pymongo
    
    mongo = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    my_db = mongo["my_db"]
    my_collection = my_db["my_collection"]
    
    # 查看一个文档
    ret = my_collection.find_one()
    print(ret)
    
    # 查看所有文档
    for document in my_collection.find():
       print(document)
    
    # 查看文档部分字段,find和find_one的第二个参数表示控制字段的显示隐藏,1为显示,0为隐藏
    for document in my_collection.find({},{ "_id": 0, "name": 1, "mobile": 1 }):
       print(document)
    
    # 条件查询
    query = { "age": 18,"name":'22' }
    document_list = my_collection.find(query)
    for document in document_list:
       print(document)
    
    # 比较运算符
    query = { "age": {"$gt":17} }
    document_list = my_collection.find(query)
    for document in document_list:
       print(document)
    
    # 排序显示
    # 单个字段排序:
    #         sort("键", 1) 升序
    #         sort("键",-1) 降序
    
    # 多个字段排序:
    #       sort([("键1",1),("键2",-1)])
    document_list = my_collection.find().sort("age",-1)
    for document in document_list:
       print(document)
       
    # 限制查询结果数量
    document_list = my_collection.find().limit(3)
    print(document_list)
    
    # 偏移、跳过
    #    skip(int)
    start = (page -1)*page_size
    document_list = my_collection.find().limit(3).skip(3) # 从第3篇文档开始获取3篇文档
    print(document_list)
    
    # 自定义条件函数
    document_list = my_collection.find({"$where":"this.age==18"})
    print(document_list)
    

    三、MongoDB应用示例:无限级评论

    1.MongoDB 工具类

    # tools/mongodb.py
    import pymongo
    from urllib import parse
    
    
    class Mongodb():
        def __init__(self):
            self.username = parse.quote_plus('admin')  # 对用户名进行编码
            self.password = parse.quote_plus('123456')  # 对密码进行编码
            self.database = "admin"  # 数据库名称
            self.host = "120.46.9.231"
            self.port = "27017"
            self.mongo = pymongo.MongoClient(
                'mongodb://%s:%s@%s:%s/%s' % (self.username, self.password, self.host, self.port, self.database))
    
            self.my_db = self.mongo["my_db"]
    
        def add_data(self, name, data):
            self.my_collection = self.my_db[name]
            ret = self.my_collection.insert_one(data)
            print(ret.inserted_id)
            return ret.inserted_id
    
        def find_where(self, name, query, pagesize, start):
            self.my_collection = self.my_db[name]
            return self.my_collection.find(query).limit(pagesize).skip(start)
    
        def find_all(self, name, query):
            self.my_collection = self.my_db[name]
            return self.my_collection.find(query)
    
        def delete_all(self,name,query):
            self.my_collection = self.my_db[name]
            return self.my_collection.delete_many(query)
    
    
    mdb = Mongodb()
    # ret = db.add_data('comment',{"title":"234234","userid":1})
    # print(ret)
    # res = db.find_all('comment')
    # for i in res:
    #     print(i)
    
    

    2.实现无限级评论逻辑

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    # Create your views here.
    from tools.mongodb import mdb
    
    
    def generate_tree(source, parent):
        tree = []
        for item in source:
            if item["pid"] == parent:
                item["children"] = generate_tree(source, item["id"])
                tree.append(item)
        return tree
    
    
    class CommemtView(APIView):
        def delete(self,request):
            mdb.delete_all('comments',{"topid":0})
            mdb.delete_all('comments',{"topid":1})
            return Response({"code": 200,"msg":"删除所有顶级数据。"})
    
        def post(self, request):
            mdb.add_data('comments', {'id': 1, "title": "第一条评论", "userid": 1, "pid": 0, "topid": 0})
            mdb.add_data('comments', {'id': 2, "title": "第二条评论", "userid": 1, "pid": 0, "topid": 0})
            mdb.add_data('comments', {'id': 5, "title": "第三条评论", "userid": 1, "pid": 0, "topid": 0})
            mdb.add_data('comments', {'id': 3, "title": "顶级评论1下回复id=1的评论", "userid": 1, "pid": 1, "topid": 1})
            mdb.add_data('comments', {'id': 4, "title": "顶级评论1下回复id=3的评论", "userid": 1, "pid": 3, "topid": 1})
            return Response({"code": 200,"msg":"POST添加评论成功。"})
    
        def get(self, request):
            page = request.GET.get('page', 1)
            page_size = 10
            start = (int(page) - 1) * page_size
            data = mdb.find_where('comments', {"pid": 0}, page_size, start)
            # mdata = list(mdb.find_all('comments',{"pid":0}))
            # count = len(mdata)
            list1 = []
            for i in data:
                dict = {"id": i['id'], 'label': i['title'], 'pid': i['pid']}
                list1.append(dict)
                son = mdb.find_all('comments', {"topid": i['id']})
                for j in son:
                    list1.append({"id": j['id'], 'label': j['title'], 'pid': j['pid']})
    
            print(data)
            resdata = generate_tree(list1, 0)
            return Response({"code": 200, 'reslist': resdata, 'tcount': 99})
    
    

    3.Vue树形结构展示无限级评论

    在这里插入图片描述

    <template>
      哈哈哈
      <div class="comment-tree">
        <el-tree
          :data="mydata"
          :props="defaultProps"
          node-key="id"
          default-expand-all
        >el-tree>
      div>
      {mydata}} -->
      {reslist}} -->
    template>
    
    <script>
    import http from '../http'
    export default {
        
      data() {
        return {
          mydata: [],
          reslist: [
            {
              id: 1,
              label: "第一条评论",
              pid: 0,
              children: [
                {
                  id: 3,
                  label: "顶级评论1下回复id=1的评论",
                  pid: 1,
                  children: [
                    {
                      id: 4,
                      label: "顶级评论1下回复id=3的评论",
                      pid: 3,
                      children: []
                    }
                  ]
                }
              ]
            },
            {
              id: 2,
              label: "第二条评论",
              pid: 0,
              children: []
            },
            {
              id: 5,
              label: "第三条评论",
              pid: 0,
              children: []
            }
          ],
          defaultProps: {
            children: 'children',
            label: 'label',
            disabled: false
          }
        };
      },
      mounted () {
        http.get('/comment/').then(res => {
            console.log("res.data.reslist===>",res.data.reslist);
            this.mydata = res.data.reslist;
        });
      },
    };
    script>
    
    <style scoped>
    .comment-tree {
      max-width: 800px;
      margin: 20px auto;
    }
    style>
    

    在这里插入图片描述

  • 相关阅读:
    Flask, Access-Control-Allow-Origin 跨域请求的解决方法
    数据库架构师之道:MySQL安装与系统整合指南
    在node.js项目中安装配置mysql模块并进行增删改查
    万界星空科技可视化数字大屏应用场景及作用
    【Linux网络】1分钟使用shell脚本完成DNS主从解析服务器部署(适用于centos主机)
    vue基础教程(7)——构建项目级首页
    Oracle数据库查询唯一约束、索引
    Maven项目创建步骤详解_smart tomcat使用介绍_Servlet项目初识(Servlet_1)
    力扣3、无重复字符串
    【PyG】理解MessagePassing过程,GCN demo详解
  • 原文地址:https://blog.csdn.net/m0_48173416/article/details/141924160