实验室简明mongoDB用户体验指南·续——查询

2016-12-18
4 min read

上篇: 2015-12-22 blog: 从MongoDB入门到编写数据库相关API

本指南延续上篇的内容,带领大家使用MongoDB Node.js Driver进行应用开发。 Node.js Driver与Mongoose之间的关系

relation about mongoDBs

可以的话,我们重新来过。

可以的话,要我弥补他犯的错。

1. 操作类型

Find——基本查询

  • find <-> select

shell: db.collection.find( , )

  • 与RDBMS比较:

query filter <-> where condition

Projection <-> select field

  • 在Driver中的写法有点不同:

db.collection(‘dbo.TBL_FAULT_INFO’).find( , )

那么我们的分页排序等操作呢?

  • 链式调用

Obj.method1().method2()……

而异步操作一般会向最后一个函数传入回调函数处理操作结果,like this:

db.collection('dbo.TBL_FAULT_INFO')
  .find({ 'EVENT_NAME': { $ne: null }, 'INFO_TIME': { $ne: null } }, { '_id': 0, 'INFO_TIME': 1, 'EVENT_NAME': 1 })
  .limit(1000)
  .sort({ 'INFO_TIME': 1 })
  .toArray(function (err, result) {
    if (err) {
      cb(err);
    } else {
      cb(null, result);
    }
  });

与之相同效果的SQL 查询:

SELECT TOP 1000 INFO_TIME, EVENT_NAME 
FROM dbo.TBL_FAULT_INFO 
WHERE EVENT_NAME IS NOT NULL and INFO_TIME IS NOT NULL 
ORDER BY INFO_TIME ASC

两者之间的映射关系:

query mapper

And more, 查询操作的其他处理方法可查阅,外援:Node.js Driver 查询操作

Aggregation——聚合操作

聚合操作就是将集合中的数据按步骤进行处理,是一种比MapReduce容易操作的批处理计算方法。

引入外援: 2016-03-03 blog: MongoDB Aggregation实践

在MongoDB 3.2之后,官方将聚合管道和Map-Reduce计算模型统称Aggregation。在我们的上下文中,还是将Aggregation限制为以.aggregate()方法为内容的计算功能。

方法

db.collection.aggregate方法中,以数组的方式传递每个stage。集合中的文档会按序传递到这些stages。

db.collection('dbo.TBL_FAULT_INFO')
  .aggregate([
    { // match stage 
      $match: { 
        'INFO_TIME': select_fault_time
      }
    },
    { // group stage
      $group: {
        '_id': '$INFO_TIME',
        'counttime': { $sum: 1 }
      }
    },
    { // limit stage
      $limit: 1000
    }
  ], function (err, result) {
    if (err) {
      cb(err);
    } else {
      cb(null, result);
    }
  });

在这里以思维导图的方式讲解我们会用到的stage。

stages

思维导图原图 其他stage方法请看,外援: Aggregation stages

2. 常见解决方案

IS NOT NULL 的条件

非空条件分为两种情况:一个是空字段,一个是内嵌空数组。我们将使用$ne表达式过滤数据,$ne的意思就是 not equal 。

{
  $match: {
    'DEBUG_CONDITION': { $ne: null }
  }
}

而过滤空数据只需要修改一个地方。

{
  $match: {
    'DEBUG_CONDITION': { $ne: [] }
  }
}

依据时间字段进行过滤

在$match stage中使用$gt(greater than)、$lt(less than)等操作符来过滤。而Javascript是MongoDB的查询语言,我们可以通过JS的Date对象来操作时间字段。

{
  $match: {
    'insert_time': { $gt: new Date('2015-08-01T00:00:00.000Z') },
    'EVENT_TYPE': 1
  }
}

内联结和左外联结的问题

内联结是什么

内联结:查询会将 A 表的每一行和 B 表的每一行进行比较,并找出满足连接谓词的组合。当连接谓词被满足,A 和 B 中匹配的行会按列组合(并排组合)成结果集中的一行。

左外联结是什么

若 A 和 B 两表进行左外连接, 那么结果表中将包含"左表"(即表 A)的所有记录,即使那些记录在"右表" B 没有符合连接条件的匹配。

SQL中JOIN默认为内联结,比如下列联结条件会将A、B表中满足A.NETNODE_NAME = B.net_node_name条件的记录合并成一行记录。

JOIN dbo.TBL_NETNODE_INFO B ON A.NETNODE_NAME = B.net_node_name 

那么在只有左外联结的MongoDB操作中就只能通过手动将A表多余的数据过滤掉。我们首先将空数组过滤,并将数组展开与原集合组合。

{
  $lookup: {
    from: 'dbo.TBL_NETNODE_INFO',
    localField: 'NETNODE_NAME',
    foreignField: 'net_node_name',
    as: 'netnodes'
  }
},
{
  $match: {
    'netnodes': { $ne: [] }
  }
},
{
  $unwind: '$netnodes'
},

分组聚合统计次数的方法

在一个场景中需要依据时间字段统计每日的记录数。

使用$substr可以对时间字符串进行截取,这里截取10个字符,也就是 ‘2016-12-31’ 。

{
  $group: {
    '_id': { $substr: ['$DEAL_TIME', 0, 10] },
    'COUNT_TIME': { $sum: 1 }
  }
}

索引导致的Error

这种情况一般出现在对集合进行排序时。由于没有索引的帮助,排序会将所有字段写入内存中。在集合数据量大时,占用的内存会达到32mb的限制。

解决方法就是创建相应的索引。

3. Q&A

答案一直到今天,才在我心中浮现。 那一瞬间 我们都没发现

comments powered by Disqus