《MongoDB管理与开发精要》——2.5节操作数据库

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 本节书摘来自华章社区《MongoDB管理与开发精要》一书中的第2章,第2.5节操作数据库,作者:红 丸,更多章节内容可以访问云栖社区“华章社区”公众号查看

2.5 操作数据库
现在就可以使用自带的MongoDB Shell工具来操作数据库了。 当然,也可以使用各种编程语言的驱动来使用MongoDB, 但自带的MongoDB Shell工具可以方便地管理数据库。
2.5.1 连接数据库
打开一个Session输入“/Apps/mongo/bin/mongo”,如果出现下面的提示,说明已经连接上数据库,可以执行操作了:

[root@localhost ~]# /Apps/mongo/bin/mongo
MongoDB shell version: 1.8.1
connecting to: test
>

默认 Shell 连接的是本机localhost 上的 test库,“connecting to:”会显示正在使用的数据库名称,想换数据库的话可以用“use mydb”来实现。
2.5.2 插入记录
建立一个things的集合并写入一些数据,建立两个对象j和t , 并保存到集合中,如下面的代码所示(其中“>”为 Shell 输入提示符):

> j = { name : "mongo" };
{"name" : "mongo"}
> t = { x : 3 };
{ "x" : 3  }
//插入数据
> db.things.save(j);
> db.things.save(t);
> db.things.find();
{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
{ "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
>

以下几点需要注意:
q 不需要预先创建一个集合,在第一次插入数据时会自动创建。
q 在文档中可以存储任何结构的数据, 但在实际应用中存储的还是相同类型文档的集合。此特性很灵活, 不需要类似alter table 语句来修改数据结构。
q 每次插入数据时,集合中都会有一个ID(_id)。
下面插入一些数据,如下面的代码所示:

//用for循环来插入数据
> for( var i = 1; i < 10; i++ ) db.things.save( { x:4, j:i } ); 
> db.things.find();
{"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")}
{"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")}
{"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")}
{"x" : 4 , "j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")}
{"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")}
{"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")}
{"x" : 4 , "j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")}
{"x" : 4 , "j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")}
{"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")}
{"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")}
请注意, 这里循环次数是10, 但是只显示到第8条, 还有2条数据没有显示。如果想继续查询下面的数据只需要使用“it”命令,如下面的代码所示:
{ "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }
has more
//此处用it执行继续查询
> it
{ "_id" : ObjectId("4c220a42f3924d31102bd868"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4c220a42f3924d31102bd869"), "x" : 4, "j" : 20 }

从技术上讲, find() 返回一个游标对象,但在上面的例子里, 并没有拿到一个游标的变量,所以 Shell 自动遍历游标,返回一个初始化的set,并允许继续用 it 迭代输出。当然,也可以直接用游标来输出,不过这是“游标”部分的内容了。
扩展阅读 什么是_id key
MongoDB支持的数据类型中,_id是其自有产物。存储在MongoDB集合中的每个文档(document)都有一个默认的主键_id,这个主键名称是固定的,它可以是MongoDB支持的任何数据类型,默认是ObjectId。在关系数据库Schema设计中,主键大多数是数值型的,比如常用的int和long,并且通常主键的取值由数据库自增获得,这种主键数值的有序性有时也表明了某种逻辑。而MongoDB在设计之初就定位于分布式存储系统,所以它不支持自增主键。
当向一个集合中写入一条文档时,系统会自动生成一个名为_id 的key,如下面的代码所示:

> db.c1.find()
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }

这里多出一个类型为ObjectId的key值,在插入时并没有指定,类似Oracle的rowid信息,这属于自动生成的。
在MongoDB中,每一个集合都必须有一个_id字段,字段类型默认是ObjectId。注意,可以不是ObjectId,例如下面的_id=3的条目:

> db.c1.find()
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
{ "_id" : 3, "name" : "Bill", "age" : 55 }

虽然_id的类型可以自由指定,但是在同一个集合中必须唯一,如果插入重复的值,系统将会抛出异常,如下面的代码所示:

> db.c1.insert({_id:3, name:"Bill_new", age:55})
E11000 duplicate key error index: test.c1.$_id_  dup key: { : 3.0 }
>

因为前面已经插入了一条_id=3的记录,所以再插入相同的文档就不允许了。
2.5.3 查询记录
在没有深入讲解查询之前, 先看看怎样从查询中返回一个游标对象。可以简单地通过 find() 来查询,返回一个任意结构的集合,而如何实现特定的查询稍后讲解。

  1. 普通查询
    一般的查询可以通过 while 循环输出,如下面的代码所示:
> var cursor = db.things.find();
> while (cursor.hasNext()) printjson(cursor.next());
{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
{ "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }

上面的例子显示了游标风格的迭代输出,hasNext() 函数用于判断是否还有数据,如果有则调用 next() 函数将数据取出来。
当使用的是 JavaScript Shell时,可以用JavaScript的forEach特性,这样就可以输出游标了。下面的例子就是使用 forEach() 循环输出数据,但forEach() 必须定义一个函数供每个游标元素调用,如下面的代码所示:

> db.things.find().forEach(printjson);
{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
{ "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }
在 MongoDB Shell 里,也可以把游标当成数组来用,如下面的代码所示:
> var cursor = db.things.find();
> printjson(cursor[4]);
{ "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }

使用游标时请注意占用内存的问题,特别是很大的游标对象,有可能会内存溢出,所以应该用迭代的方式来输出。下面的示例是把游标转换成真实的数组类型:

> var arr = db.things.find().toArray();
> arr[5];
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }

注意 这些特性只是在MongoDB Shell里使用,不是所有的其他应用程序驱动都支持。如果有其他用户在集合里第一次或者最后一次调用next(), 可能得不到游标里的数据,所以要明确地锁定要查询的游标。

  1. 条件查询
    下面的示例说明了如何执行一个类似SQL的查询,并演示了如何在 MongoDB 里实现,这是在MongoDB Shell里查询,当然,也可以用其他的应用程序驱动或者语言来实现。

查询条件是 { a:A, b:B, ... } ,类似“where a==A and b==B and ...”。例如,SQL查询:

SELECT * FROM things WHERE x=4
用MongoDB 实现:
> db.things.find({x:4}).forEach(printjson);
{ "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }
上面显示的是所有元素,也可以返回特定的元素,类似于返回表里某字段的值,只需要在“find({x:4})”里指定元素的名称,如下所示:
> db.things.find({x:4}, {j:true}).forEach(printjson);
{ "_id" : ObjectId("4c220a42f3924d31102bd856"), "j" : 1 }
{ "_id" : ObjectId("4c220a42f3924d31102bd857"), "j" : 2 }
{ "_id" : ObjectId("4c220a42f3924d31102bd858"), "j" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "j" : 4 }
{ "_id" : ObjectId("4c220a42f3924d31102bd85a"), "j" : 5 }

上面查询命令中的“{j:true}”显式地指明结果集只返回列“j”的值,而其他列如“x”的值并没有返回。

  1. findOne()语法
    MongoDB Shell为了避免游标可能带来的开销,提供了一个findOne() 函数。这个函数和 find() 函数一样,不过它返回的是游标里的第一条数据,或者返回null,即空数据。

例如name=“mongo” 可以用很多方法来实现,如用 next() 来循环游标或者当成数组返回第一个元素,而用 findOne() 方法更简单和高效,如下面的代码所示:

> printjson(db.things.findOne({name:"mongo"}));
{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
  1. 通过limit限制结果集数量
    如果需要限制结果集的长度,可以调用limit方法,如下面的代码所示:
> db.things.find().limit(3);
{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
{ "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
{ "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }

强烈推荐这种解决性能问题的方法,通过限制条数来减少网络传输,同时,limit方法也广泛应用于分页技术中。

2.5.4 修改记录
如果需要修改表中的记录,可以调用update方法。
例如,将列name的值从“mongo”修改为“mongo_new”,如下面的代码所示:

db.things.update({name:"mongo"},{$set:{name:"mongo_new"}});

接下来通过执行“db.things.find()”命令查询列name的值是否改过来了,如下面的代码所示:

> db.things.find(); 
{ "_id" : ObjectId("4faa9e7dedd27e6d86d86371"), "x" : 3 }
{ "_id" : ObjectId("4faa9e7bedd27e6d86d86370"), "name" : "mongo_new" }

经验证,name的值已经改为“mongo_new”了。
2.5.5 删除记录
如果要删除表中的记录,可以调用remove方法。
例如,将用户name是“mongo_new”的记录从集合things中删除,如下面的代码所示:

> db.things.remove({name:"mongo_new"});
> db.things.find();                    
{ "_id" : ObjectId("4faa9e7dedd27e6d86d86371"), "x" : 3 }

经验证,该记录确实被删除了。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
2月前
|
存储 JSON NoSQL
学习 MongoDB:打开强大的数据库技术大门
MongoDB 是一个基于分布式文件存储的文档数据库,由 C++ 编写,旨在为 Web 应用提供可扩展的高性能数据存储解决方案。它与 MySQL 类似,但使用文档结构而非表结构。核心概念包括:数据库(Database)、集合(Collection)、文档(Document)和字段(Field)。MongoDB 使用 BSON 格式存储数据,支持多种数据类型,如字符串、整数、数组等,并通过二进制编码实现高效存储和传输。BSON 文档结构类似 JSON,但更紧凑,适合网络传输。
81 15
|
2月前
|
存储 NoSQL Cloud Native
MongoDB云原生化:为企业开发注入高效动力
MongoDB云原生化为企业开发注入高效动力,分为三部分:1. 介绍阿里云和MongoDB的服务;2. 阿里云MongoDB解决自建模型痛点的功能,包括隔离性、海量数据处理、弹性能力及运维操作优化;3. 客户案例展示。通过云原生架构,MongoDB实现了灵活的扩展、高效的备份恢复和快速的回档能力,显著提升了企业的业务迭代速度和数据管理效率。典型客户如吉比特、莉莉丝、掌阅等受益于这些功能,实现了更稳定和高效的数据库服务。
|
2月前
|
存储 NoSQL 关系型数据库
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
我们的风控系统引入阿里云数据库MongoDB版后,解决了特征类字段灵活加减的问题,大大提高了开发效率,极大的提升了业务用户体验,获得了非常好的效果
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
|
3月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第21天】本文探讨了MongoDB Atlas的核心特性、实践应用及对云原生数据库未来的思考。MongoDB Atlas作为MongoDB的云原生版本,提供全球分布式、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了云原生数据库的未来趋势,如架构灵活性、智能化运维和混合云支持,并分享了实施MongoDB Atlas的最佳实践。
|
4月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第20天】本文探讨了MongoDB Atlas的核心特性、实践应用及对未来云原生数据库的思考。MongoDB Atlas作为云原生数据库服务,具备全球分布、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了实施MongoDB Atlas的最佳实践和职业心得,展望了云原生数据库的发展趋势。
|
4月前
|
存储 NoSQL MongoDB
MongoDB 数据库引用
10月更文挑战第20天
41 1
|
4月前
|
存储 NoSQL MongoDB
mongodb的数据库表怎么创建
在此过程中,理解并掌握这些基本操作,是深入探索MongoDB魅力,乃至构建高效数据解决方案的关键所在。通过实践,您将更加深刻地体会到这种随需应变的数据管理模式带来的便利与效率提升。
96 0
|
4月前
|
存储 关系型数据库 MySQL
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景比较
|
5月前
|
存储 NoSQL 关系型数据库
非关系型数据库-MongoDB技术(二)
非关系型数据库-MongoDB技术(二)
|
5月前
|
NoSQL 关系型数据库 MongoDB
非关系型数据库-MongoDB技术(一)
非关系型数据库-MongoDB技术(一)

热门文章

最新文章