美文网首页
2020-07-20--爬虫项目 -02--mongodb的使用

2020-07-20--爬虫项目 -02--mongodb的使用

作者: program_white | 来源:发表于2020-07-20 23:29 被阅读0次

为什么用MongoDB?

传统的计算机应用大多使用关系型数据库来存储数据,比如大家可能熟悉的MySql, Sqlite等等,它的特点是数据以表格(table)的形式储存起来的。数据库由一张张排列整齐的表格构成,就好像一个Excel表单一样,每个表格会有若干列,比如一个学生信息表,可能包含学号、姓名、性别、入学年份、高考成绩、籍贯等等。而表格的每一排,则是一个个学生的具体信息。在企业级应用和前互联网时代,关系型数据库几乎是不二选择。关系型数据库的特点是有整齐划一的组织,很方便对数据进行描述、插入、搜索。
想象有一个传统的网上服装商店吧,它的主要的数据可能是储存在一张叫products的表单里,表单可能包含这些列:商品编号(ID)、名称(Name)、商家(brand)、主目录(cate)、子目录(sub-cat)、零售价(price)、是否促销(promotion)等等。如果有一个用户想要查找所有价格低于300元的正在促销的鞋子的编号和名称,则可以执行类似于以下的SQL语句:

SELECT ID, name FROM products WHERE cate='shoes' AND price<300 and AND promotion=true;

有时会涉及到复杂的跨表查询,需要大量使用join语句。这种跨表查询不仅降低了查询速度,而且这些语句写起来也不简单。

那么,如果用MongoDB数据库来实现,可以如何设计数据模型呢?很简单,像下面这样[1]

 _id: POST_ID
   title: TITLE_OF_POST, 
   description: POST_DESCRIPTION,
   author: POST_BY,
   tags: [TAG1, TAG2, TAG3],
   likes: TOTAL_LIKES, 
   comments: [    
      {
         user:'COMMENT_BY',
         message: TEXT,
         dateCreated: DATE_TIME,
      },
      {
         user:'COMMENT_BY',
         message: TEXT,
         dateCreated: DATE_TIME,
      }
   ]

在MongoDB里,每篇博客文章以一个文档(document)的形式保存起来,而文档内部包含了很多项目,比如title tags等,每一个项目都是key-value的形式,即有一个项目的名字,比如title,以及它的值TITLE_OF_POST。而重要的是,一个key可以有多个values,他们用[]括起来。

这种“宽松”的数据存储形式非常灵活,MongoDB不限制每个key对应的values的数目。比如有的文章没有评论,则它的值就是一个空集,完全没有问题;有的文章评论很多,也可以无限制地插入。更灵活的是,MongoDB不要求同一个集合(collection,相当于SQL的table)里面的不同document有相同的key,比如除了上述这种文档组织,有的文档所代表的文章可能没有likes这个项目,再比如有的文章可能有更多的项目,比如可能还有dislikes等等。这些不同的文档都可以灵活地存储在同一个集合下,而且查询起来也异常简单,因为都在一个文档里,不用进行各种跨文档查询。而这种MongoDB式的存储也方便了数据的维护,对于一篇博客文章来说,所有的相关数据都在这个document里面,不用去考虑一个数据操作需要involve多少个表格。

当然,除了上述的优点,MongoDB还有不少别的优势,比如MongoDB的数据是用JSON(Javascript Object Notation)存储的(就是上面的这种key-value的形式),而几乎所有的web应用都是基于Javascript的。因此,存储的数据和应用的数据的格式是高度一致的,不需经过转换。更多的优点可以查看:[2]

创建集合和删除集合

在IntelliShell中编写命令,新建一个数据库:

use tutorial         #新建tutorial数据库

显示数据库:

show databases

在mongodb中如果数据库中没有数据则不显示该数据库。

我们试着往我们的数据库里添加一个集合(collection)
MongoDB里的集合和SQL里面的表格是类似的:

db.createCollection('author')

顺利的话会显示:

{ "ok" : 1 }

表示创建成功。
你可以再回头执行:

show databases

演示:

//创建数据库studb
use studb;
//创建一个集合
db.createCollection('author')
//显示数据库
show databases;

返回ok

这时候我们的author集合已经位列其中。你可以再执行

show collections

可以看到创建的集合author也在其中。

我们暂时不需要author这个集合,所以我们可以通过执行:

db.author.drop()

来将其删除。这时候你再执行show collections,就再也看不到我们的author了。

这一节要记住的点主要只有一个:集合(collection)类似于SQL的表格(table),类似于Excel的一个个表格。

插入数据

想象一个精简版的“豆瓣电影”。我们需要创建一个数据库,来存储每部电影的信息,电影的信息包括:

  • 电影名字
  • 导演
  • 主演(可能多个)
  • 类型标签(可能多个)
  • 上映日期
  • 喜欢人数
  • 不喜欢人数
  • 用户评论(可能多个)
  • 显然我们需要先创建一个叫电影的集合:
db.createCollection('movie')

然后,我们就可以插入数据了:

db.movie.insert(
{
    xanme:"灰猎犬号",
    doc:"亚伦-施耐德",
    actors:['汤姆·汉克斯','斯蒂芬·格拉汉姆','伊丽莎白·苏'],
    pub:new Date(2020,7,10),
    commons:[{
        uname:'凌睿',
        cdate:new Date(2020,7,12),
        des:'汤姆·汉克斯把士兵、上尉、列车长、船长、舰长、机长、宇航员、狱警、FBI、工程师、符号专家、报社编辑、律师、制片人、玩具、汽车……全都演了个遍,人生圆满了。',
    },
    {
        uname:'南辕北辙',
        cdate:new Date(2020,7,10),
        des:'汤叔captain专业户!电影全程无尿点,值得一看'
    },]
});

请注意,这里插入数据之前,我们并不需要先声明movie这个集合里面有哪些项目。我们直接插入就可以了~这一点和SQL不一样,SQL必须先声明一个table里面有哪些列,而MongoDB不需要。

把上面的例子复制进命令行应该可以顺利运行,但我强烈建议你手动打一下,或者输入一部你自己喜欢的电影。insert操作有几点需要注意:

  • \1. 不同key-value需要用逗号隔开,而key:value中间是用冒号;
  • \2. 如果一个key有多个value,value要用[]。哪怕当前只有一个value,也加上[]以备后续的添加;
  • \3. 整个“数据块”要用{}括起来;

如果你在insert之后看到WriteResult({ "nInserted" : 1 }),说明写入成功。

这个时候你可以用查询的方式来返回数据库中的数据:

db.movie.find().pretty()

演示:

//创建数据库moviedb
use moviedb;
//创建一个集合
db.createCollection('movie');
//向集合中插入数据
db.movie.insert(
{
    xanme:"灰猎犬号",
    doc:"亚伦-施耐德",
    actors:['汤姆·汉克斯','斯蒂芬·格拉汉姆','伊丽莎白·苏'],
    pub:new Date(2020,7,10),
    commons:[{
        uname:'凌睿',
        cdate:new Date(2020,7,12),
        des:'汤姆·汉克斯把士兵、上尉、列车长、船长、舰长、机长、宇航员、狱警、FBI、工程师、符号专家、报社编辑、律师、制片人、玩具、汽车……全都演了个遍,人生圆满了。',
    },
    {
        uname:'南辕北辙',
        cdate:new Date(2020,7,10),
        des:'汤叔captain专业户!电影全程无尿点,值得一看'
    },]
});
db.movie.find()

仔细观察find()的结果,你会发现多了一个叫'_id'的东西,这是数据库自动创建的一个ID号,在同一个数据库里,每个文档的ID号都是不同的。

我们也可以同时输入多个数据:

db.movie.insert([
    {
    xanme:"塘鹅暗杀令",
    doc:"亚伦-施耐德",
    actors:['朱莉娅·罗伯茨','丹泽尔·华盛顿','山姆·夏普德'],
    pub:new Date(1993,12,17),
    commons:[{
            uname:'山姆·夏普德',
            cdate:new Date(2011,2,120),
            des:'90年代的中国,在音像店中最常看到的光碟影片之一,以铁盒包装。怕是因为“揭露了美帝的丑恶”吧?',
            },
            {
            uname:'夜丫儿',
            cdate:new Date(2012,9,2),
            des:'这是部太有名的电影,却一直没看过。现在看来有些太过理想化了吧。'
            },
        ]    
    },
    {
    xanme:"惊唇劫 Kiss the Girls",
    doc:"亚伦-施耐德",
    actors:['摩根·弗里曼','艾什莉·贾德','加利·艾尔维斯'],
    pub:new Date(1997,11,13),
    commons:[{
        uname:'九尾黑猫',
        cdate:new Date(2008,8,7),
        des:'贾德的悬疑系列片里最好看的一个',
    },
    {
        uname:'滕雅望',
        cdate:new Date(2011,12,03),
        des:'司法心理学家,某些场景,竟然跟《杀人的回忆》很相似⋯⋯'
    },]
    },
])

顺利的话会显示:

BulkWriteResult({
    "writeErrors" : [ ],
    "writeConcernErrors" : [ ],
    "nInserted" : 2,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]

表面我们成功地插入了两个数据。注意批量插入的格式是这样的:db.movie.insert([{ITEM1},{ITEM2}])。几部电影的外面需要用[]括起来。

请注意,虽然collection的插入不需要先声明,但表达相同意思的key,名字要一样,比如,如果我们在一个文档里用directed_by来表示导演,则在其它文档也要保持同样的名字(而不是director之类的)。不同的名字不是不可以,技术上完全可行,但会给查询和更新带来困难。

好了,到这里,我们就有了一个叫moviedb的数据库,里面有一个叫movie的集合,而movie里面有三个记录。接下来我们就可以对其进行查询了。

查询

在上一节我们已经接触到最简单的查询db.movie.find().pretty()。MongoDB支持各种各样的深度查询功能。先来一个最简单的例子,

单个条件查询

找出汤姆·汉克斯主演的所有电影:

db.movie.find({'actors':'汤姆·汉克斯'}).pretty()

查询结果:

多个条件查询

也可以设置多个条件。比如找出亚伦-施耐德导演的, 汤姆·汉克斯主演的电影:

db.movie.find({'actors':'汤姆·汉克斯','doc':'亚伦-施耐德'}).pretty()

查询结果:

这里两个条件之间,是AND的关系,只有同时满足两个条件的电影才会被输出。同理,可以设置多个的条件,不赘述。

条件之间也可以是或的关系,比如查找汤姆·汉克斯主演或亚伦-施耐德导演的电影

db.movie.find({$or : [{'actors' : '汤姆·汉克斯'},{'doc' : '亚伦-施耐德'}]}).pretty();

查找结果:
三个电影都查找出来,因为他们的导演都是亚伦-施耐德。
注意这里面稍显复杂的各种括号。

范围搜索

这里需要在数据库中插入一个属性项,也就是更新操作。
为每个电影添加一个值likes--喜欢人数

db.movie.update({'xanme':'灰猎犬号'},{$set:{'likes':128023}});

更新结果:

那么比如找出50万人以上赞的电影:

db.movie.find({likes:{$gt:110000}}).pretty()

类似地,少于二十万人赞的电影:

db.movie.find({likes:{$lt:200000}}).pretty()

类似的运算符还有:lte:小于或等于;gte:大于或等于;ne:不等于;:等于。

注意,对于包含多个值的value的,同样可以用find来查询。比如:

db.movie.find({'标签':'恐怖'}).pretty()

返回 灰猎犬号,假设该对象有多个标签,也会返回。

如果你确切地知道返回的结果只有一个,也可以用findOne:

db.movie.findOne({'xanme':'灰猎犬号'})

如果有多个结果,则会按磁盘存储顺序返回第一个。请注意,findOne()自带pretty模式,所以不能再加pretty(),将报错。

如果结果很多而你只想显示其中一部分,可以用limit()和skip(),
limit(m):指明输出的个数m
skip(n):指明从第n+1个结果开始数
常用于分页功能。

db.movie.find().limit(2).skip(1).pretty()

则跳过第一部,从第二部开始选取两部电影。

局部查询

第五节的时候我们讲了find的用法,但对于符合条件的条目,我们都是返回整个JSON文件的。这类似于SQL里面的SELECT *。有的时候,我们需要的,仅仅是部分数据,这个时候,find的局部查询的功能就派上用场了。

//查询喜欢大于110000的电影的导演和电影名
db.movie.find({likes:{$eq:110000}},{'doc':1,'xanme':1})

结果:


这里find的第二个参数是用来控制输出的,1表示要返回,而0则表示不返回。默认值是0,但_id是例外,因此如果你不想输出_id,需要显式地声明:

db.movie.find({likes:{$eq:110000}},{'doc':1,'xanme':1,'_id':0})

结果:

更新

很多情况下你需要更新你的数据库,比如有人对某部电影点了个赞,那么你需要更新相应的数据库。比如有人对《灰猎犬号》点了个赞,而它本来的赞的个数是128000,那么你需要更新到128001。可以这样操作:

//将电影名为灰猎犬号的电影的喜欢人数改为128001,如果集合数据中没有该属性则自动创建并赋值。
db.movie.update({'xanme':'灰猎犬号'},{$set:{likes:128001}})

第一个大括号里表明要选取的对象,第二个表明要改动的数据。请注意上述的操作相当不现实,因为你首先要知道之前的数字是多少,然后加一,但通常你不读取数据库的话,是不会知道这个数(134370)的。
上述的set方法还可以再集合中国创建属性,并赋值。

MongoDB提供了一种简便的方法,可以对现有条目进行增量操作。假设又有人对《七宗罪》点了两个赞,则可以:

db.movie.update({'xanme':'灰猎犬号'},{$inc:{likes:2}})

注意如果有多部符合要求的电影。则默认只会更新第一个。如果要多个同时更新,要设置{multi:true},像下面这样:

db.movie.update({}, {$inc:{likes:10}},{multi:true})

但是前提是你要改变的数据必须数据类型一致。

注意,以上的更新操作会替换掉原来的值或者创建数据属性,但是如果本来有一个属性,对应了多个值。
所以如果你是想在原有的属性列表中基础上增加一个值的话,则应该用$push
比如,为《灰猎犬号》添加一个演员。

db.movie.update({'xanme':'灰猎犬号'},{$push:{actors:'李钊'}})

结果:

删除

删除的句法和find很相似,比如,要删除标签为romance的电影,则:

db.movie.remove({'xanme':'灰猎犬号'})

考虑到我们数据库条目异常稀少,就不建议你执行这条命令了~

注意,上面的例子会删除所有标签包含romance的电影。如果你只想删除第一个,则

db.movie.remove({'xanme':'灰猎犬号'},1)

如果不加任何限制:

db.movie.remove({})

会删除movie这个集合下的所有文档。

相关文章

  • 2020-07-20--爬虫项目 -02--mongodb的使用

    为什么用MongoDB? 传统的计算机应用大多使用关系型数据库来存储数据,比如大家可能熟悉的MySql, Sqli...

  • 2020-07-21--爬虫项目 -02--mongodb的使用

    索引和排序 为文档中的一些key加上索引(index)可以加快搜索速度。这一点不难理解,假如没有没有索引,我们要查...

  • 爬虫就业冲刺20180818

    一、教学内容 1、使用scrapy实现之前的音乐爬虫 教学内容: 复习之前的音乐爬虫项目 scrapy使用进阶 使...

  • windows环境下安装Python Scrapy

    学习背景 由于最近项目需要爬虫获取数据,现学习python语言,可使用pthon原生爬虫和scrapy框架两种爬虫...

  • Scrapy的用法

    1.第一步:创建爬虫项目 2.使用pycharm打开爬虫项目 打开结果如下(目录结构): 3.第三步:创建爬虫说明...

  • Scrapy爬虫项目创建

    1.新建一个爬虫项目 可以使用 scrapy startproject 项目名称 2.创建一个自己的爬虫文件 sc...

  • mm131爬虫(scrapy)

    Scrapy 基本使用 1. Install 2. 新建爬虫项目 3. 新建爬虫,在 spiders 目录下创建(...

  • scrapy输出到文件字符编码设置

    使用scrapy命令行工具建立了爬虫项目(startproject),并使用scrapy genspider建立了...

  • 认识Scrapy框架

    开发python,从程序的复杂程度可分为:爬虫项目和爬虫文件。 使用Scrapy可以提高开发效率。 Scrapy安...

  • scrapy入门使用及pycharm远程调试

    一·scrapy的入门使用 scrapy的安装 创建scrapy项目 创建scrapy爬虫:在项目目录下执行 运行...

网友评论

      本文标题:2020-07-20--爬虫项目 -02--mongodb的使用

      本文链接:https://www.haomeiwen.com/subject/lcdukktx.html