MongoDB学习笔记(四) 用MongoDB的文档结构描述数据关系

MongoDB的集合(collection)可以看做关系型数据库的表,文档对象(document)可以看做关系型数据库的一条记录。但两者并不完全对等。表的结构是固定的,MongoDB集合并没有这个约束;另外,存入集合的文档对象甚至可以嵌入子文档,或者“子集合”。他们最终都可以用类似于BJSON的格式描述。我们今天就来分析MongoDB这一特性带来的独特数据管理方式。我们还是以samus驱动为例来分析,samus驱动支持两种方式访问数据库,基本方式和linq方式,基本方式在上篇以介绍过,linq方式我不想单独讲解应用实例,这篇我会用两种方式来对比介绍。

一、包含子文档的集合操作

  有这么一个应用场景,某网站提供会员登录的功能,用户需要注册账号才能享受会员服务,但是注册者可能会因为用户资料表单输入项过大而放弃填写,因此用户信息分为主要资料和详细资料两项,初次注册只需要填写主要资料就行了。我们打算把详细信息设计为子文档存储。

   1) linq方式实现

  1. 新建数据描述类,描述用户信息

代码如下:

/// <summary>
/// 用户主要资料
/// </summary>
public class UserInfo
{
    public string UserId { get; set; }
    public string UserName { get; set; }
    public string PassWord { get; set; }
    public Detail Detail { get; set; }
}

/// <summary>
/// 用户详细资料
/// </summary>
public class Detail
{
    public string Address { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

2. 我们要新建一个用户业务操作类“UserBLL”。这个时候要让驱动知道UserInfo类描述了“用户资料”的字段信息,在GetMongo()方法实现了配置步骤,UserBLL完整代码如下:

代码如下:

public class UserBLL
{
    public string connectionString = "mongodb://localhost";
    public string databaseName = "myDatabase";

private Mongo mongo;
    private MongoDatabase mongoDatabase;

//注意这里泛型类型为“UserInfo”
    private MongoCollection<UserInfo> mongoCollection;

public UserBLL()
    {
        mongo = GetMongo();
        mongoDatabase = mongo.GetDatabase(databaseName) as MongoDatabase;
        mongoCollection = mongoDatabase.GetCollection<UserInfo>() as MongoCollection<UserInfo>;
        mongo.Connect();
    }
    ~UserBLL()
    {
        mongo.Disconnect();
    }

/// <summary>
    /// 配置Mongo,将类UserInfo映射到集合
    /// </summary>
    private Mongo GetMongo()
    {
        var config = new MongoConfigurationBuilder();
        config.Mapping(mapping =>
        {
            mapping.DefaultProfile(profile =>
            {
                profile.SubClassesAre(t => t.IsSubclassOf(typeof(UserInfo)));
            });
            mapping.Map<UserInfo>();
        });
        config.ConnectionString(connectionString);
        return new Mongo(config.BuildConfiguration());
    }
}

3. 接着,在“UserBLL”类中定义一个方法“InsertSomeData()”来插入一些数据:

代码如下:

/// <summary>
/// 插入一些数据
/// </summary>
public void InsertSomeData()
{
    UserInfo userInfo1 = new UserInfo()
    {
        UserId = "1001",
        UserName = "张三",
        PassWord = "123456"
    };
    mongoCollection.Save(userInfo1);

UserInfo userInfo2 = new UserInfo()
    {
        UserId = "1002",
        UserName = "李四",
        PassWord = "123456",
        Detail = new Detail()
        {
            Address = "湖北",
            Age = 20,
            Email = "lisi@163.com"
        }
    };
    mongoCollection.Save(userInfo2);

UserInfo userInfo3 = new UserInfo()
    {
        UserId = "1003",
        UserName = "王五",
        PassWord = "123456",
        Detail = new Detail()
        {
            Address = "广东",
            Age = 20,
            Email = "wangwu@163.com"
        }
    };
    mongoCollection.Save(userInfo3);

UserInfo userInfo4 = new UserInfo()
    {
        UserId = "1004",
        UserName = "赵六",
        PassWord = "123456",
        Detail = new Detail()
        {
            Address = "湖北"
        }
    };
    mongoCollection.Save(userInfo4);
 }

4. 定义一个查找数据的方法“Select”,它将查找用户详细信息中,地址在湖北的全部用户:

代码如下:

/// <summary>
/// 查询详细资料地址为湖北的用户信息
/// </summary>
public List<UserInfo> Select()
{
    return mongoCollection.Linq().Where(x => x.Detail.Address == "湖北").ToList();
}

5. 还定义一个删除数据的方法,将删除集合全部数据:

代码如下:

/// <summary>
/// 删除全部用户信息
/// </summary>
public void DeleteAll()
{
    mongoCollection.Remove(x => true);
}

6. 在Main方法中添加如下代码:

代码如下:

static void Main(string[] args)
{

UserBLL userBll = new UserBLL();
    userBll.InsertSomeData();
    var users = userBll.Select();
    foreach (var user in users)
    {
        Console.WriteLine(user.UserName + "是湖北人");
    };
    userBll.DeleteAll();
}

 7. 最后执行程序,打印如下信息:

李四是湖北人
赵六是湖北人

   1) 普通实现

  普通方式实现不想多讲,直接贴代码,看看与linq方式有什么区别:

代码如下:

class Program
{
    static void Main(string[] args)
    {
        UserBLL userBll = new UserBLL();
        userBll.InsertSomeData();
        var users = userBll.Select();
        foreach (var user in users)
        {
            Console.WriteLine(user["UserName"].ToString() + "是湖北人");
        };
        userBll.DeleteAll();

Console.ReadLine();
    }
}

public class UserBLL
{
    public string connectionString = "mongodb://localhost";
    public string databaseName = "myDatabase";
    public string collectionName = "UserInfo";

private Mongo mongo;
    private MongoDatabase mongoDatabase;
    private MongoCollection<Document> mongoCollection;

public UserBLL()
    {
        mongo = new Mongo(connectionString);
        mongoDatabase = mongo.GetDatabase(databaseName) as MongoDatabase;
        mongoCollection = mongoDatabase.GetCollection<Document>(collectionName) as MongoCollection<Document>;
        mongo.Connect();
    }
    ~UserBLL()
    {
        mongo.Disconnect();
    }

/// <summary>
    /// 插入一些数据
    /// </summary>
    public void InsertSomeData()
    {
        Document userInfo1 = new Document();
        userInfo1["UserId"] = "1001";
        userInfo1["UserName"] = "张三";
        userInfo1["PassWord"] = "123456";
        mongoCollection.Save(userInfo1);

Document userInfo2 = new Document();
        userInfo2["UserId"] = "1002";
        userInfo2["UserName"] = "李四";
        userInfo2["PassWord"] = "123456";
        //子文档
        var userInfo2Detail = new Document();
        userInfo2Detail["Address"] = "湖北";
        userInfo2Detail["Age"] = 20;
        userInfo2Detail["Email"] = "lisi@163.com";
        userInfo2["Detail"] = userInfo2Detail;
        mongoCollection.Save(userInfo2);

Document userInfo3 = new Document();
        userInfo3["UserId"] = "1003";
        userInfo3["UserName"] = "王五";
        userInfo3["PassWord"] = "123456";
        var userInfo3Detail = new Document();
        userInfo3Detail["Address"] = "广东";
        userInfo3Detail["Age"] = 20;
        userInfo3Detail["Email"] = "wangwu@163.com";
        userInfo3["Detail"] = userInfo3Detail;
        mongoCollection.Save(userInfo3);

Document userInfo4 = new Document();
        userInfo4["UserId"] = "1004";
        userInfo4["UserName"] = "赵六";
        userInfo4["PassWord"] = "123456";
        var userInfo4Detail = new Document();
        userInfo4Detail["Address"] = "湖北";
        userInfo4["Detail"] = userInfo4Detail;
        mongoCollection.Save(userInfo4);

}

/// <summary>
    /// 查询详细资料地址为湖北的用户信息
    /// </summary>
    public IEnumerable<Document> Select()
    {
        return mongoCollection.Find(new Document { { "Detail.Address", "湖北" } }).Documents;
    }

/// <summary>
    /// 删除全部用户信息
    /// </summary>
    public void DeleteAll()
    {
        mongoCollection.Remove(new Document { });
    } 
}

最后,我们通过这段代码输出全部用户资料信息的BJSON格式:

代码如下:

/// <summary>
/// 打印数据BJSON
/// </summary>
public void PrintBJSON()
{
    string BJSON = string.Empty;
    foreach (var documet in mongoCollection.FindAll().Documents)
    {

BJSON += documet.ToString();

}
    Console.WriteLine(BJSON);
}

结果如下:

代码如下:

{ "UserId": "1001", "UserName": "张三", "PassWord": "123456", "_id": "4d80ec1ab8a4731338000001" }
{ "UserId": "1002", "UserName": "李四", "PassWord": "123456", "Detail": { "Address": "湖北", "Age": 20, "Email": "lisi@163.com" }, "_id": "4d80ec1ab8a4731338000002" }
{ "UserId": "1003", "UserName": "王五", "PassWord": "123456", "Detail": { "Address": "广东", "Age": 20, "Email": "wangwu@163.com" }, "_id": "4d80ec1ab8a4731338000003" }
{ "UserId": "1004", "UserName": "赵六", "PassWord": "123456", "Detail": { "Address": "湖北" }, "_id": "4d80ec1ab8a4731338000004" }

二、包含“子集合”的集合操作

  同样举个例子:有一个学校人事管理系统要统计班级和学生的信息,现在定义了一个“班级集合”,这个集合里面的学生字段是一个“学生集合”,包含了本班全部学生。

   1) linq方式实现

  基础配置我就不多说了,数据类定义如下:

代码如下:

/// <summary>
/// 班级信息
/// </summary>
public class ClassInfo
{
    public string ClassName { get; set; }
    public List<Student> Students { get; set; }
}

/// <summary>
/// 学生信息
/// </summary>
public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

查询叫“张三”的学生在哪个班级,以及他的详细信息:

(这里其实是ToList后在内存中查的,linq方式直接查询好像驱动不支持。)

代码如下:

public List<ClassInfo> Select()
{
    return mongoCollection.Linq().ToList().Where(x => x.Students.Exists(s => s.Name == "张三")).ToList();
}

1) 普通实现

  查询叫“张三”的学生在哪个班级,以及他的详细信息:

代码如下:

public List<Document> Select()
{
    var mongocollection = mongoDatabase.GetCollection("ClassInfo");
    return mongocollection.Find(new Document { { "Students.Name", "张三" } }).Documents.ToList();
}

打印数据的BJSON:

代码如下:

{ "_id": "4d814bae5c5f000000005f63", "ClassName": "1001", "Students": [ { "Name": "张三", "Age": 10 }, { "Name": "李四", "Age": 0 } ] }
{ "_id": "4d814bae5c5f000000005f64", "ClassName": "1002", "Students": [ ] }
{ "_id": "4d814bae5c5f000000005f65", "ClassName": "1003", "Students": [ { "Name": "王五", "Age": 11 }, { "Name": "赵六", "Age": 9 } ] }

三、小结

 通过本节例子我们发现,MongoDB有它独特的文档结构可以描述数据对象之间的一些关系特征。它虽然没有关系型数据库多表符合查询那样强大的表间查询方式,但也可以通过文档结构描述更灵活的关系特性,可以这么说,关系型数据库能做的,MongoDB基本上也可以做到。甚至有些关系数据库不容易做到的,MongoDB也可以轻松做到,比如,描述数据类的继承关系等。

作者:李盼(Lipan)
出处:[Lipan] (http://www.cnblogs.com/lipan/)

(0)

相关推荐

  • MongoDB快速入门笔记(四)之MongoDB查询文档操作实例代码

    MongoDB简介 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 下面给大家介绍MongoDB查询文档操作的实例 先把student删除,再重新插入数据 > db.student.drop() true > db.student.insert([{ "_id" : 1, "

  • MongoDB快速入门笔记(三)之MongoDB插入文档操作

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 本文给大家介绍MongoDB的插入文档的方法,一起看看吧 1.文档的数据存储格式为BSON,类似于JSON.MongoDB插入数据时会检验数据中是否有"_id",如果没有会自动生成. shell操作有insert和save两种方法.当插入一条数据有

  • MongoDB快速入门笔记(六)之MongoDB删除文档操作

    MongoDB是一个跨平台,面向文档的数据库,提供高性能,高可用性和易于扩展.MongoDB是工作在集合和文档上一种概念. 文档是一组键值对.文档具有动态模式.动态模式是指,在同一个集合的文件不必具有相同一组集合的文档字段或结构,并且相同的字段可以保持不同类型的数据. db.集合名称.remove({query}, justOne) query:过滤条件,可选 justOne:是否只删除查询到的第一条数据,值为true或者1时,只删除一条数据,默认为false,可选. 准备数据:把_id为1和2

  • MongoDB快速入门笔记(六)之MongoDB的文档修改操作

    MongoDB MongoDB 是一个开源的文档数据库,并领先的 NoSQL 数据库. MongoDB 是由 c++语言编写. 文档 文档是一组键 - 值对.文件动态模式.动态模式是指,在相同集合中的文档不需要具有相同的字段或结构组的公共字段的集合的文档,可以容纳不同类型的数据. db.集合名称.update({query},{update},upsert, multi}) query:过滤条件 update:修改内容 upsert:如果不存在查询条件查出的记录,是否插入一条数据,默认是fals

  • MongoDB中对文档的增删查改基本操作方法总结

    插入文档:insert() 方法 要插入数据到 MongoDB 集合,需要使用 MongoDB 的  insert() 或 save() 方法. 语法: insert() 命令的基本语法如下: >db.COLLECTION_NAME.insert(document) 例子:  >db.mycol.insert({    _id: ObjectId(7df78ad8902c),    title: 'MongoDB Overview',     description: 'MongoDB is

  • MongoDB插入、更新、删除文档实现代码

    1 创建数据库并插入数据 use jinxt db.adou.insert({name:"jinxt",age:"28"}); //刚创建的数据库 jinxt并不在数据库的列表中, 要显示它,我们需要向 jinxt数据库插入一些数据 show dbs db.dropDatabase(); //删除数据库 2 插入文档 use jinxt db.adou.insert({name:"jinxt",age:28,sex:"男",t

  • MongoDB修改、删除文档的域属性实例

    由于本博使用的博客程序是边开发边使用的,所以开发过程中动态创建了某些现在不需要的属性 MongoDB 是无 Schema 的,不像关系数据库那样列属性定义在表而非记录中,MongoDB 的集合中的每个文档可以拥有各自不同的域属性. MongoDB 中使用 db.collections.update 修改集合中若干文档的域属性,使用 $set 增加域,$unset 删除域. 删除集合中所有文档的一个域 复制代码 代码如下: db.posts.update({}, { $unset: { delet

  • PHP库 查询Mongodb中的文档ID的方法

    在IBM我的一份新工作是一名开发的后勤人员.那意味着我的大部分时间是在和数据库打交道.在我的工作流程中,我花了一些时间在MongoDB上面--这是一个文档数据库.但是在通过ID来检索记录这个操作上面我碰到了一些问题.下面的代码是最终版本,以后碰到类似的问题我可以直接引用它.如果大家也需要,希望下面对大家有所帮助. MongoDB 和 IDs 当我向一个集合中插入数据的时候,我并没有设置_id字段:如果这个字段是空的话,那么MongoDB将要自动生成一个ID来使用,这对我来说是非常不错的.然而,当

  • MongoDB学习笔记(四) 用MongoDB的文档结构描述数据关系

    MongoDB的集合(collection)可以看做关系型数据库的表,文档对象(document)可以看做关系型数据库的一条记录.但两者并不完全对等.表的结构是固定的,MongoDB集合并没有这个约束:另外,存入集合的文档对象甚至可以嵌入子文档,或者"子集合".他们最终都可以用类似于BJSON的格式描述.我们今天就来分析MongoDB这一特性带来的独特数据管理方式.我们还是以samus驱动为例来分析,samus驱动支持两种方式访问数据库,基本方式和linq方式,基本方式在上篇以介绍过,

  • MongoDB 学习笔记(一)-MongoDB配置

    MongoDB简介 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 步入正题: 下载MongoDB 下载地址:https://www.mongodb.com/download-center?jmp=nav 这里是在windows平台下安装MongoDB, 下载后,在本机,按提示进行安装. 注: 这个安装只

  • MongoDB学习笔记(五) MongoDB文件存取操作

    由于MongoDB的文档结构为BJSON格式(BJSON全称:Binary JSON),而BJSON格式本身就支持保存二进制格式的数据,因此可以把文件的二进制格式的数据直接保存到MongoDB的文档结构中.但是由于一个BJSON的最大长度不能超过4M,所以限制了单个文档中能存入的最大文件不能超过4M.为了提供对大容量文件存取的支持,samus驱动提供了"GridFS"方式来支持,"GridFS"方式文件操作需要引入新的程序集"MongoDB.GridFS.

  • 微信小程序学习笔记之跳转页面、传递参数获得数据操作图文详解

    本文实例讲述了微信小程序学习笔记之跳转页面.传递参数获得数据操作.分享给大家供大家参考,具体如下: 前面一篇介绍了微信小程序表单提交与PHP后台数据交互处理.现在需要实现点击博客标题或缩略图,跳转到博客详情页面. 开始想研究一下微信小程序的web-view组件跳转传参,把网页嵌入到小程序,结果看到官方文档的一句话打消了念头,因为没有认证...... [方法一 使用navigator组件跳转传参] 前台博客列表页面data.wxml:(后台数据交互参考上一篇) <view wx:for="{

  • Vuejs学习笔记之使用指令v-model完成表单的数据双向绑定

    表单类控件承载了一个网页数据的录入与交互,本章将介绍如何使用指令v-model完成表单的数据双向绑定. 6.1 基本用法 表单控件在实际业务较为常见,比如单选.多选.下拉选择.输入框等,用它们可以完成数据的录入.校验.提交等. Vue.js提供了v-model指令,用于在表单类元素上双向绑定数据,例如在输入框上使用时,输入的内容会实时映射到绑定的数据上. 例如下面的例子: <div id="app"> <input type="text" v-mo

  • asp.net下用Aspose.Words for .NET动态生成word文档中的数据表格的方法

    1.概述 最近项目中有一个这样的需求:导出word 文档,要求这个文档的格式不是固定的,用户可以随便的调整,导出内容中的数据表格列是动态的,例如要求导出姓名和性别,你就要导出这两列的数据,而且这个文档不是导出来之后再调整而是导出来后已经是调整过了的.看到这里,您也许马上想到用模板导出!而且.NET中自带有这个组件:Microsoft.Office.Interop.Word,暂且可以满足需求吧.但这个组件也是有局限性的,例如客户端必须装 office组件,而且编码复杂度高.最麻烦的需求是后面那个-

  • JSP程序运行原理、文档结构及简单输入输出实例分析

    本文实例讲述了JSP程序运行原理.文档结构及简单输入输出.分享给大家供大家参考.具体如下: 目标: 掌握Web应用的文档结构: 掌握JSP的运行原理: 掌握JSP的简单输入和输出. 主要内容: 通过一个简单实例介绍Web应用的文档结构和运行原理: 通过一个简单的注册功能介绍基本的输入输出. 实现内容:客户端验证. 1. 文档结构 每个应用都有一个根目录,例如ch2:理论上可以放在任何地方,但是需要配置,简单的做法,直接放在了webapps这个目录下,在这个目录的应用会被自动加载. 在根目录下会有

  • 小程序中读取腾讯文档的表格数据的实现

    目录 1 创建连接器 2 创建腾讯文档 3 应用中访问腾讯文档 3.1 获取sheet中的所有数据 3.2 迭代行和列的数据 4 总结 日常生活中我们使用腾讯文档在线的收集各类数据,数据收集是比较方便,但是如果希望对数据进行维护或者后续统计分析还是不方便的.本篇就介绍一下如何利用微搭低代码工具来接入腾讯文档的数据,实现数据的在线管理功能. 1 创建连接器 如果希望接入腾讯文档的功能,需要创建连接器.打开微搭控制台,点击新建连接器 选择腾讯文档 然后进行授权 输入连接器的名称和标识,点击开始新建

  • MongoDB学习笔记(一) MongoDB介绍与安装方法

    一.前言 最近开始学习非关系型数据库MongoDB,却在博客园上找不到比较系统的教程,很多资料都要去查阅英文网站,效率比较低下.本人不才,借着自学的机会把心得体会都记录下来,方便感兴趣的童鞋分享讨论.部分资源出自其他博客,旨将零散知识点集中到一起,如果有侵犯您的权利,请联系li-pan2@163.com.大部分内容均系原创,欢迎大家转载分享,但转载的同时别忘了注明作者和原文链接哦. 二.MongoDB简介 MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的

随机推荐