您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15419|回复: 0
打印 上一主题 下一主题

[php学习资料] MongoDB高级查询用法大全

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
版本一:7 |* U# \8 D0 E: y7 _! L
  a" e; Q- s; z" V
1 ) . 大于,小于,大于或等于,小于或等于
; J1 `5 |# H: s% Y) H6 P: l' @+ P, ]: M3 B* I2 H
$gt:大于2 e) l& }% T8 l7 u/ Q' B
$lt:小于
# W' }- z7 ?( D2 Y& G# J* Z3 k$ h, I- _$gte:大于或等于
& D& i* K  z1 q: l( V% s; m$lte:小于或等于, o( Q' I* D& k: E$ |5 s  F

/ o9 F0 x( M% e8 b例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value% J! a' W! [- Q0 K& g' q7 g4 }
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    7 _# b8 P" _/ y% M. s5 u
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value7 h" W3 m6 Y9 m/ W$ S# O
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
' G! J0 g( \1 N. u* V
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    $ A& n/ p+ D" p/ X+ O
  2. db.things.find({j : {$gte: 4}});
复制代码
. H. `; i9 \& G6 t& E2 t+ [3 N
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
% h5 I& J1 k" V
7 m* g* v$ N( ~) T6 Y

: u9 q( L& n* c1 [
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

: a7 J' h0 D2 x( d, w2 [! Y
3) in 和 not in ($in $nin)! a) A% x1 U3 }) i  S

! U: P: @. j1 B语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
$ U6 h$ d$ ]3 p5 ^
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    3 B& @3 m) g/ N! o1 {! H
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
; q% Z# j3 {& Z) i2 e! P
' T1 ?& D! \3 `
4) 取模运算$mod3 {3 _6 a8 Y% {7 M0 G, f' ]6 x
% m1 K* Y' Y$ u2 D1 S7 B
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

7 ~" ~* e! B8 f+ {* y% R" f
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

- g/ ?; \" `; `

% q5 l! j; s- j- N# d+ Q. G' ]5)  $all) r) m" T) S, F8 U

! u0 g7 u7 e; ~# j. m; R. B$all和$in类似,但是他需要匹配条件内所有的值:+ E: C3 N6 F0 ?

: r* K; h0 h2 Y; {$ W) u3 G; o如有一个对象:- D: s& }- A) X. x, r( K4 M: r
  1. { a: [ 1, 2, 3 ] }
复制代码
% E. F% m) d  W5 [* Y5 y+ s
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
# y2 x2 d0 c7 j. h6 a8 M8 ?
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

' G( b$ P: U; s6 A1 N
9 K( i8 S  Z5 I) o0 U, S% K% v) x
6)  $size' B) j  g0 r/ K$ `" J3 V$ }
9 c- B; c5 U+ T2 {0 K& R
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:; B' e: Z9 ?4 I0 k) S: i

( d( O. Z, Q; f, t! O下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
. q+ J7 l8 q/ S7 T
官网上说不能用来匹配一个范围内的元素,如果想找$size<5之类的,他们建议创建一个字段来保存元素的数量。
You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.

! ]7 T- M. A1 E0 d4 X  g
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
      Q  a  }6 D( k1 o
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
9 L+ ]5 j7 N# a& u3 j* y  u7 ]* N
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string  G% u. }$ d0 A
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

. O8 p, A, K# {: ~* p
9)正则表达式
* |2 [" V, n+ {
0 x# u3 A& y2 w+ c% S5 pmongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
8 H1 H3 o0 d3 C: q" L
10)  查询数据内的值- O, y3 k  }) z7 Q8 o$ x' l
. ~2 W5 y- n  d/ c8 u
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
) b  G% G( {! O( S& \
11) $elemMatch
  h! F. \0 [; E+ r( O7 d6 @* O. T; D+ D0 p9 i; V
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    5 t) F; _- ]8 n% p* j
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    + I8 {% m, q# S  d: l
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]8 c7 |: V+ h" D
  4. }
复制代码

7 M7 `: X: s3 [% u, ]5 H6 S. L/ W$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
% E8 C# [, |( \+ L9 W" E
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
* o0 Z( e/ _: ^! x% e1 p5 b" o. @7 i0 S
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

! ]/ c: J3 n' L7 w: ]4 e* h& c
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
5 V3 {' H9 Z  A0 S: B( A
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
+ x# ]5 t2 j- f8 V
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

- C1 \3 l& s2 i3 h
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

3 o3 W( p4 x+ ~- e  z: G0 c$ A/ D
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

( F- ^) b+ e; `
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    - b3 J3 A+ [4 p' L! l9 N8 w0 q8 M: O
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

# |& i% a1 g% L
mongodb还有很多函数可以用,如排序,统计等,请参考原文。; f' r& C2 V$ G0 d- s$ Y
2 Q& J  Q% {! R
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:/ \% d# i# C9 M) N0 \

/ M- e; l0 P7 E0 Dhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
, s$ R4 i2 Q' \+ j8 ~- X$ j3 `6 s
4 a, I% k$ N, I版本二:
7 v* {8 `/ e5 Q" p+ ?9 G
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
* F. |! S3 Q% g2 H) P/ O: i
  1. use admin
复制代码

$ w6 w1 B4 V6 I# A  J& F7 x
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
& ?; g/ V/ S& q9 r/ ?3 ?6 o
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

- S/ a! Z5 S0 \  _
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

! V! U6 p' ?) N* s- f
         5. #删除用户
  1.           db.removeUser('name')
复制代码
2 L8 q( ], A- F5 Z+ o, y
         6. #查看所有用户
  1.           show users
复制代码

/ i3 c+ C. d& h  F( y8 f, l
         7. #查看所有数据库
  1.           show dbs
复制代码

8 Z$ h1 B" F5 y2 t! Y# X% U
         8. #查看所有的collection
  1.           show collections
复制代码

* h1 R# R. x8 T
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

$ B: K. _2 @  h& Y% U
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
1 i1 ]0 T. a$ u: i
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

9 M! B/ c6 u, r6 z  k, ^  ?5 X
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
7 L0 {4 G. Y, V, i3 U5 H
        13. #查看profiling
  1.           show profile
复制代码

  W' G  Z/ X) Q/ Q( K" a
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
, t# [0 {8 s8 U- ]3 L- c: m
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

; c8 i+ a3 I" e  \0 z
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
: z& t" z; c: _8 a8 w5 V
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
4 j0 p; f5 f: G% O
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
+ T. N; n5 y+ R$ j5 Q# D4 B0 L
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

9 I5 C0 a* M5 ?; _0 t: y
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
: j' P& ^9 n2 Q' N) w6 M
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
$ v2 t- S8 T( V- Z0 l2 i5 B! Q
   3. 索引
         1. #增加索引:1(ascending),-1(descending)
         2. db.foo.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
         3. #索引子对象
         4. db.user_addr.ensureIndex({'Al.Em': 1})
         5. #查看索引信息
         6. db.foo.getIndexes()
         7. db.foo.getIndexKeys()
         8. #根据索引名删除索引
         9. db.user_addr.dropIndex('Al.Em_1')
   4. 查询
         1. #查找所有
        2. db.foo.find()
        3. #查找一条记录
        4. db.foo.findOne()
        5. #根据条件检索10条记录
        6. db.foo.find({'msg':'Hello 1'}).limit(10)
        7. #sort排序
        8. db.deliver_status.find({'From':'ixigua@sina.com'}).sort({'Dt',-1})
         9. db.deliver_status.find().sort({'Ct':-1}).limit(1)
        10. #count操作
        11. db.user_addr.count()
        12. #distinct操作,查询指定列,去重复
        13. db.foo.distinct('msg')
        14. #”>=”操作
        15. db.foo.find({"timestamp": {"$gte" : 2}})
        16. #子对象的查找
        17. db.foo.find({'address.city':'beijing'})
   5. 管理
         1. #查看collection数据的大小
         2. db.deliver_status.dataSize()
         3. #查看colleciont状态
         4. db.deliver_status.stats()
         5. #查询所有索引的大小
         6. db.deliver_status.totalIndexSize()

7 j2 w9 B  m* J
6.  高级查询
条件操作符
# `% |, d9 q! I/ J& k9 [
  1. $gt : >
    ' u" T' V) R1 [* Y) V6 o
  2. $lt : <
    0 @$ m( W- l& x9 N0 T
  3. $gte: >= # j( T+ e4 V# H$ E0 F. w  D% [
  4. $lte: <= % L0 q3 r. v- r4 M* s+ t$ r
  5. $ne : !=、<> " y  o3 x! R7 z! ]
  6. $in : in
    : H2 d4 `! I( i( o' T: v; s! y
  7. $nin: not in ) [9 s5 p5 Y/ }+ G2 y
  8. $all: all
    6 n& \: z4 L  w( @3 j2 h
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
8 N3 }& k) m2 c2 L' X

, Q2 u( ?! O1 d  n查询 name <> "bruce" and age >= 18 的数据   ~, b( Z+ ?6 i" o7 P4 w) ^
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

; y  s1 V" ?+ o! o
8 |3 |( M1 Y) E- o查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 & H1 @6 ]  p, r- _. K! v+ m9 A' g
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

" n* }6 I8 s) J9 |/ i; u& x# [" Z2 r: u- k& @
查询 age in (20,22,24,26) 的数据 7 }! K+ \6 X3 N" u* P$ B
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

" e( b2 r- }$ ~$ `+ h- F) c; I, V0 w: }
查询 age取模10等于0 的数据 7 o( w3 |# n: R2 l# [% Q
  1. db.users.find('this.age % 10 == 0');
复制代码

% N3 ?8 d8 E2 i5 r5 m0 }或者
$ I0 p( `' }# _) I% K
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

' T- J% J  `. l1 ]3 C
% \( s( s, S4 e. H" R& B* R匹配所有 % W5 s5 f9 b* X# L3 ~) S! A- X
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% g( {. J" b0 ~4 D4 c
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
" i% K& F# H. [8 t0 z可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 3 O- H! t$ H3 y/ G/ `$ t6 ^+ U" {' H

. w/ M6 \% K/ w$ Y3 l5 t- p& k查询不匹配name=B*带头的记录   u/ g+ T# P5 c( P  v1 e0 q/ u
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

  C6 b3 v* |2 J- ~0 W0 T1 w查询 age取模10不等于0 的数据 5 a* f& b  G1 e% V  W) ?
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

8 I, Q3 M9 U' u8 M; K, ^) E  g. K- o$ p$ V! w- `
#返回部分字段 - I+ K) C) |( j* p" s0 N- @
选择返回age和_id字段(_id字段总是会被返回) % ?6 Q6 b  r0 Y; I9 e: y
  1. db.users.find({}, {age:1}); 8 _" J& R5 t. v& i+ x- N8 ~
  2. db.users.find({}, {age:3}); : j$ ?* q/ \* Q4 {) D4 D
  3. db.users.find({}, {age:true});
      m( ?! i, U& Y/ T  h* `  L
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
4 K- b3 b4 K- R$ G; r1 U
0为false, 非0为true , e! U5 Y, }4 u% B
* Q$ V- T$ E% W  K
选择返回age、address和_id字段
: m# |) b" C* d+ V& S( K
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

  [0 H+ v+ e/ V9 Y3 D& y, s0 S% T1 o8 U# S9 _3 P: `+ k% i3 S
排除返回age、address和_id字段
* A  F: n/ c6 Z6 b
  1. db.users.find({}, {age:0, address:false}); 7 B1 x" t1 r" H% o% _
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
2 a  P7 C: ?, `( c

2 q9 E) s# b  c* a7 q数组元素个数判断 ! N/ d; E5 a' L& B  L& H
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
# v: B! L/ g1 F匹配db.users.find({favorite_number: {$size: 3}});
3 G; \* v* X& ?' F# Z2 M# L. t不匹配db.users.find({favorite_number: {$size: 2}});
8 o4 s) N1 p$ v" c# N/ O. N( e9 h: l+ r; b
$exists判断字段是否存在
/ J+ O& c# x  Q查询所有存在name字段的记录
  k9 w* Q8 ]2 ?: S, U* f+ J
  1. db.users.find({name: {$exists: true}});
复制代码

: ^7 c" v- ]& F: _6 J/ N: L查询所有不存在phone字段的记录 , c( h) d; H( T+ O# R9 R# K
  1. db.users.find({phone: {$exists: false}});
复制代码

% t2 V+ p" }0 x( {
# U$ Z7 E$ `4 x5 h, Z$type判断字段类型 : b: G& e* {' f, Q- x! @
查询所有name字段是字符类型的
+ G0 h( x+ d+ u5 x
  1. db.users.find({name: {$type: 2}}); 9 _0 Q' a- y  a
复制代码
- f2 i! @$ O3 v( M' J
查询所有age字段是整型的
4 ]( S, M- ?0 B4 H+ i6 R! F1 l
  1. db.users.find({age: {$type: 16}}); 3 h5 y+ T0 \7 f1 N( s5 @1 I; z
复制代码

3 F9 U. H5 x3 q0 N8 X8 e, J$ x) J对于字符字段,可以使用正则表达式 8 K* W  Z0 o. p, t8 L. L2 }7 v" R
查询以字母b或者B带头的所有记录
1 L9 @; o: \8 H3 v. A6 l
  1. db.users.find({name: /^b.*/i}); 9 j+ k& H/ T* b& r1 T
复制代码

5 b# ~' q) d  L( @$ h. G; F$elemMatch(1.3.1及以上版本) 2 Q0 F5 W! R2 a7 D0 o
为数组的字段中匹配其中某个元素
! a$ n! x* z+ H% r( Y9 F
6 S; p1 i, X/ kJavascript查询和$where查询
+ }% L  l: J% \' S) K0 a% o" G8 h查询 age > 18 的记录,以下查询都一样 9 c1 @( U2 W; S5 h: x7 \
  1. db.users.find({age: {$gt: 18}}); 7 K" F5 F" Q5 W9 a' O( K+ i* @
  2. db.users.find({$where: "this.age > 18"});
    2 I+ ?4 F7 J  N! h! H' \3 w" S
  3. db.users.find("this.age > 18"); 8 a. U( s8 f! u: [3 H
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

( ~% e1 g% |( v
7 a1 d2 e8 d; B% j2 o' C7 t排序sort()
9 h6 C1 P7 b( ~3 h% R" O以年龄升序asc 9 ~' l$ z( ^% L' z& K
  1. db.users.find().sort({age: 1});
    7 \# o+ {8 ?/ s3 M" s% m
复制代码

" C7 y. T3 D) Z2 Q& d6 L+ {以年龄降序desc + d* R# ]0 y& G. x1 E5 @3 e
  1. db.users.find().sort({age: -1});
    9 E! h: Q, w7 n
复制代码

, ^2 c$ p6 P3 O  U限制返回记录数量limit() ) I1 Y7 y1 o) T- `9 p7 C! a$ c
返回5条记录
$ V. K+ j) i  I. I) ?5 z/ I
  1. db.users.find().limit(5);
    ) j. w4 _- d. [, t2 E7 [+ W) H+ K4 c8 |
复制代码
- {( _% @9 p. _0 i
返回3条记录并打印信息 4 r0 @/ ?4 I: J- k
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); + H" V  \4 I# F4 N( N3 u
复制代码
5 _$ v8 F# A9 k( X3 l$ W
结果 1 v7 j; B- W3 n* C7 _) R8 P% Y
  1. my age is 18 ; R( x! h7 P6 h. V! M4 `5 J8 }* }
  2. my age is 19 6 h( K8 C$ r0 t3 Q
  3. my age is 20
复制代码

* n7 D' n4 \6 R( x0 R6 h7 R; X, i+ ?  q, F! i3 P3 t. p- ?3 Q
限制返回记录的开始点skip()
: r1 o* q# m* A7 Q$ X8 e4 c从第3条记录开始,返回5条记录(limit 3, 5)
* J& b& i4 [" E, q
  1. db.users.find().skip(3).limit(5); 9 W* A5 |7 \; U
复制代码

% r" q5 ~9 j3 K( Z3 l% Q; t查询记录条数count()
: Z% o; Y0 M% O/ p) l5 Ddb.users.find().count(); ' |4 D; e( B7 Z& g4 U
db.users.find({age:18}).count();
/ @" h) _+ V2 z" c以下返回的不是5,而是user表中所有的记录数量 . N; W" g  ^% @7 r
db.users.find().skip(10).limit(5).count(); " H& ~. u5 t; X8 e5 f/ b3 |
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) ! o+ c- I& I% V- c- T3 _+ w5 U
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
& |3 ]6 i7 T8 K  ~
6 A& p: G' a; K- [8 y1 L' ^6 U9 l
分组group() 2 p8 G8 O, M: J
假设test表只有以下一条数据 % x+ ~- [; K! a4 I: S- h
  1. { domain: "www.mongodb.org"
      B; ^( ^/ t' y! D" u$ I' F
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} ( s# y* P. Y2 l0 S" h2 k- u
  3. , response_time: 0.05
    9 G8 u5 K6 ^: _& ~8 Y
  4. , http_action: "GET /display/DOCS/Aggregation" " u6 O( a7 J" p: F, H2 ~4 F
  5. }
复制代码
# P8 Y6 p' I5 h+ e( C0 z
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
0 D& ]2 U; c$ K( t% A- z
  1. db.test.group(
    0 L0 P! q+ y% f) `
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    9 `3 Q- [  v5 |' `0 o; R. m
  3. , key: {http_action: true} ' B8 F3 |+ J9 b! i3 f* d) D7 D  P
  4. , initial: {count: 0, total_time:0}   d) g5 q; T8 X6 K) m
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    - V# X9 O. q- L( W3 f. J- m
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ! L! X( L& w$ k' Y6 {) M5 w
  7. } ); . g$ K( U+ o" N+ v- F# N
  8. % U2 N! H+ c* b4 j: C
  9. [ 0 q6 C9 |. F' T' G& a$ X3 x
  10. { 0 ?: z# e3 Y( \/ F: C/ a# k9 M# m/ V
  11. "http_action" : "GET /display/DOCS/Aggregation",
    * E/ P* l, c; L3 o& R
  12. "count" : 1, 0 E5 V1 c' U0 R5 d; D$ N
  13. "total_time" : 0.05,
    6 y7 R1 [3 o8 z8 ]( B; V, E. E
  14. "avg_time" : 0.05
    + y) s! X$ d2 @% v0 N+ c
  15. } . V+ [' `# [. ^8 s- X4 p
  16. ]
复制代码
( Q1 z6 {! B1 c8 N+ z5 W
: \- l: j# b+ }: P( t# q$ |
- p0 H% V% X: B
MongoDB 高级聚合查询
MongoDB版本为:2.0.8
系统为:64位Ubuntu 12.04
先给他家看一下我的表结构[Oh sorry, Mongo叫集合]
如你所见,我尽量的模拟现实生活中的场景。这是一个人的实体,他有基本的manId, manName, 有朋友[myFriends],有喜欢的水果[fruits],而且每种水果都有喜欢的权重。
很不好的是你还看见了有个“_class”字段? 因为我是Java开发者, 我还喜欢用Spring,因此我选用了Spring Data Mongo的类库[也算是框架吧,但是我不这么觉得]。
现在有很多人Spring见的腻了也开始烦了。是的,Spring野心很大,他几乎想要垄断Java方面的任何事情。没办法我从使用Spring后就离不开他,以至于其他框架基本上都不用学。我学了Spring的很多,诸如:Spring Security/Spring Integration/Spring Batch等。。。不发明轮子的他已经提供了编程里的很多场景,我利用那些场景解决了工作中的很多问题,也使我的工作变得很高效。从而我又时间学到它更多。Spring Data Mongo封装了mongodb java driver,提供了和SpringJDBC/Template一致编程风格的MongoTemplate。
不说废话了,我们直接来MongoDB吧。
  • Max 和Min
    ' s6 {: x6 T: ^/ c* K4 i) K
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

  ^7 S2 d3 P" o# D
: z2 x7 F7 R$ H- q, x" h" H
" I* L! A" V( k$ V+ s- Q
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    ; A$ L$ K5 \, O3 ~/ U+ H  U! ?0 ~
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
* v1 E; {& {; k% c6 @
( J) _, u9 P9 n- W/ ?' q
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

1 e8 l, {& ?* k, {. ^
  \, Q+ p7 ], S% D) R7 f
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
. P; r; M3 T* Z; A5 n- |, n1 _
9 \& C8 ^% b$ T2 v9 _. ?4 Y* w
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
2 m+ U* V) Y* d' o( N& V
* Y( G% {4 r: [% Z2 b
输出如:
  1.         
    + _9 x; z. I- R2 k, B; Y
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

+ x/ K; C) C5 O- b* T8 k  T- [9 Q5 [6 G

1 E- G; X3 q2 y
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    , a" C6 y2 O1 u( _
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    $ T& s8 m/ X% d2 ~( H# ^2 h
  3.        xmlns:context="http://www.springframework.org/schema/context"
    / t9 a" l5 }9 u" q, o$ H
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"/ B. }# L; `+ X7 T  [
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans& X9 v- N  Q+ v+ X, Y" P9 c( m! {8 |
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" k+ u. Q4 \0 ]
  7.           http://www.springframework.org/schema/context9 ]$ W! u5 m/ z+ L$ P: a& Y
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    . V! S  B7 r: \7 T; |0 H% B
  9.           http://www.springframework.org/schema/data/mongo
    9 N  m0 C  g& S4 o* f2 z
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">5 j  c4 E' e7 |& |9 |% H

  11. 6 T) C4 v) L6 g2 e$ H
  12.     <context:property-placeholder location="classpath:mongo.properties" />* H; ?! A4 o4 m7 K

  13. % X. |0 U1 C, |, n8 C: U5 j
  14.     <!-- Default bean name is 'mongo' -->
    ! I# d. p3 [2 Q; H
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
      V4 M  n9 ~6 F  i0 Z+ j( p4 {( g$ R

  16. 0 q4 A, p6 D* e* |: p
  17.     <mongo:db-factory id="mongoDbFactory"8 t3 Q: x9 m9 J0 |9 E
  18.                   mongo-ref="mongo"/ Q+ \9 s" |. ^5 x/ u# ~0 E$ }
  19.                   dbname="mongotest" />
    ' Z: W$ y, u4 @  l' E- R9 h

  20. ( d  d; u% T& S9 |% I
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    % r! M0 K( o1 I
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>0 z( p0 n8 ^8 t5 q: t! C. @' d
  23.     </bean>; F% w2 L. J/ k# m1 F
  24. </beans>
复制代码

$ V8 W, h, w% r" n2 U4 w0 B4 B
9 S& ~& h& \# m. ]" k
maxmin的测试
  1. @Test
    5 ^5 @3 u4 g: X$ x+ c5 t4 x6 E
  2.     public void testMaxAndMinAge() throws Exception {/ I% f9 i2 n1 x( B4 |3 M+ Y0 d# z$ ^
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);" l- e9 o- Q; v6 {
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    4 g1 p' L2 @$ [9 M* P' N+ T- {: c( F
  5.         log.info(result);
    , K* G! c( T. {/ a$ _0 e9 s" [
  6. : E6 R) @0 g% e0 ]! h; j' z7 |* c
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ; N7 Y  \1 V: ?& K
  8.         result = mongoTemplate.findOne(q, Person.class);
    ) S$ h" G* A: `
  9.         log.info(result);
      o3 F2 b4 ~# ]2 c5 |: l
  10.     }
复制代码

8 f1 t+ m9 Z+ X* V  J
+ C: ^" x  e8 |9 Q+ o. H
distinct的测试:
  1. @Test- n1 k/ ]( O, c+ N4 x
  2.     public void testDistinct() throws Exception {. o: c8 j4 F! U
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    : P3 U( Y# |( Y/ c* D+ q
  4.         for (Object o : result) {( q7 \8 |- Y$ R7 w
  5.             log.info(o);
    ; [; m' U( @2 W
  6.         }9 w0 B$ D2 O* a2 o4 v1 X- q

  7. 9 [- z: r7 j; r
  8.         log.info("==================================================================");6 B: {6 E3 B6 z0 r& e
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));* R1 G; J, s4 s* l
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());: g- E3 N9 v8 g. ~& Q$ D
  11.         for (Object o : result) {
    % n4 O8 c4 d& T* R& s
  12.             log.info(o);
    4 y# F9 ?/ j( K# _7 m
  13.         }
    & ~# y7 {0 P/ E# m% w* }

  14. # D' s5 A: E2 E3 F# J3 z' G
  15.         log.info("==================================================================");( D+ f$ V& A( _
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");' r, B/ G1 v% I% f' C# t. n
  17.         for (Object o : result) {* Y2 W2 \" G, ?& y) i
  18.             log.info(o);' K+ X- v. S! E5 @6 o* e
  19.         }
    7 x' P* n% ]- X. ?: @8 `
  20.     }
复制代码
8 E% V/ n: q# F* P5 U* u, Y

$ s7 x( o- z5 I8 @2 Y9 C
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    6 a6 M/ B9 I4 R5 y- `
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    + q# @3 x7 p: e: h2 v7 v
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    & ~1 r% y- ?  D* P# z
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876542 N# ~% j0 a0 ?. B! [. O: ?# q& m
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni3 b) S6 K! }! Z# F! ?
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    # y$ u& u( N1 }# o2 V
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456  T. c; E2 `# N% b2 f7 O- q/ m
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    6 e6 G# q. g1 v& g, j. L4 @
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    . [5 i- b& S  `* u. |
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 3456788 h- b0 F5 i( ^5 P
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567897 L6 c  S+ O( |! E3 O
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654* f0 f, _( C2 c1 m
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    7 k/ C! V0 R! Z; h3 t7 |
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    $ w+ p/ t  M) X! z
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    + w# [% o: s" r6 X
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    ' m- {$ C  @( u5 S8 A- z  U; }
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www& z6 h2 }9 V) w8 H- Q; D
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    * W5 K9 J  \8 Y0 j+ |4 L  f( e
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    & b1 j- O. A" x1 ]8 r
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
      ]: g5 z. Y4 Q
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
      O. p) y) g5 x. s+ R4 _
  22. 12-22 14:13:45 [INFO] [support.GenericApplicationContext(1020)] Closing org.springframework.context.support.GenericApplicationContext@1e0a91ff: startup date [Sat Dec 22 14:13:44 CST 2012]; root of context hierarchy
复制代码

7 b. N- v4 X7 ~7 Q8 Q; Z4 W0 D0 S
6 F/ d; c0 X# `' M
这里我要特别说明一下, 当使用了Spring Data Mongo,如上面的findOne(query, Person.class)它就会把查询的结果集转换成Person类的对象。Spring Data Mongo的很多API中都这样,让传入了一个Bean的class对象。因为distinct的测试是输出list<String>的,我 使用的mongo-java-driver的api。他们都很简单,唯一的是Query这个Spring提供的对象,希望读者注意,他几乎封装了所有条件 查询,sort,limit等信息。
! D$ g# `- A4 |: I

+ J) e$ P& x/ c8 O5 J; B' Y  a3 B( {. ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 15:02 , Processed in 0.079890 second(s), 23 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!