MongoDB中的$in和$elemMatch

PC客户端开发多年,一直想涉足下Web开发,进入15年,想起14年有一个计划是用ruby写一个网站,已经无法完成了!亡羊补牢也不晚,于是动手搞起,打算山寨goodreads的quotes板块,已经草草的实现了部分功能-看这里, 其中数据库部分使用到是MongoDB, 使用MongoDB的原因是新鲜、好玩、简单,MongoDB确实比较容易理解,花2个小时看了一遍the-little-mongodb-book就可以上手干活了。

但高级些的用法还是需要细读官方文档,不然还是会出错,最近自己就在$in和$elemMatch上栽跟头,花费了大把时间。

1
{ _id: 1, quote: "不要着急,最好的总会在最不经意的时候出现", author: 泰戈尔, tags: [ "哲理", "人生" ]}

比如(上面的例子),我需要根据tag哲理查找tags中包含哲理的记录,怎样写query语句呢?借助于万能的google,$in和$elemMatch很快进入了我的视线,从字面理解,$in是查询指定field是否在某个集合中,看mongo的官方文档$in的用法也确实是这样讲的:

The $in operator selects the documents where the value of a field equals any value in the specified array.

一眼看去,并不适于我们的需求。再看看$elemMatch:

The $elemMatch operator matches documents in a collection that contain an array field with at least one element that matches all the specified query criteria.

$elemMatch专门用于查询数组Field中元素是否满足指定的条件。看起来适合我们的需求,像这样:

1
 db.items.find({"tags": {$elemMatch: {$equal: "哲理"}}}) ;错误

上面的用法是错误的,因为mongo并没有$equal查询指令, 所以我们无法用$elemMatch达成我们的需求。

当发现$elemMatch无法满足功能需求时,自己陷入了错误的方向:怀疑用错了$elemMatch, 然后就一直在网上看别人如何使用$elemMatch的, 而没有回头看下$in到用法,直到走投无路时。我发现$in到第二个用处:

Use the $in Operator to Match Values in an Array

并且官方示例和自己的需求场景几乎一模一样,接着当然自己很快实现了按tag查找的功能:

1
db.items.find({"tags": {$in: ["哲理"]}})

总结下$in和$elemMatch:

  • $in要查询的Field可以是普通值也可以是数组,而$elemMatch则是专门用于查询array Field的。
  • $in的查询相对简单,主要是查询值或数组中某个值是否在待查询列表中.
  • $elemMatch的查询则比较复杂,是查询Array Field中的元素是否满足一系列的查询条件。