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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:9 j) O5 M8 b! E5 o5 Y# Q1 J

# m4 _3 r0 p" U6 |4 n) ?* `2 c1 ) . 大于,小于,大于或等于,小于或等于8 ?+ n" m, v* U  r& V2 j
0 ]% F8 r; |9 n) N
$gt:大于( I2 W% _. b! x$ s+ s$ y: P
$lt:小于: r2 z1 W# P2 u8 |
$gte:大于或等于1 F+ C# [( F/ Y/ o/ O
$lte:小于或等于6 w7 p+ K! b- P4 L1 E

. s) v# G) l" l6 K2 k& f9 C$ V例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    2 V' w; K+ ^3 |6 h
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    , ]$ G/ m; o/ G
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    - {) I% w2 L) G% M) A; b5 N
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

0 b; a! L3 a- Q* K
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    6 T: H! R! {( m" L& }
  2. db.things.find({j : {$gte: 4}});
复制代码
8 B- J* J* H7 _, c. @
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

4 \# i9 Z+ A8 y- `0 a/ m, R
9 X# ]$ B6 M& N3 h7 G; W" p
& d6 R* B8 F: `* b8 N
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

9 ]) n, {8 `& \0 I5 B1 U
3) in 和 not in ($in $nin)6 J% }; \! W- ^

( z' M( J8 T4 B/ Q3 r! Q2 ~3 l语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

/ d0 B/ }* n- _# ~  ~& Z
例子:
  1. db.things.find({j:{$in: [2,4,6]}});4 q' m/ g" o8 V* u9 ]
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

7 {7 N0 ~/ S2 U5 \* W# U. g% S& ~

3 }& v; Q* g( Y7 E- F4) 取模运算$mod4 F7 S" j7 [" ^/ P- i% N  N$ U

2 B# W$ J; P8 e; b3 N/ `6 l' `如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

/ I  \3 Q7 `. t2 M3 v
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

& F& O1 O5 Z" X. y. z/ N1 d9 s

: k- o+ [8 G6 m5)  $all) \; @: ^5 ~* R* P
  b0 I5 @+ `) [" h9 p6 R; i2 O3 P1 q0 x
$all和$in类似,但是他需要匹配条件内所有的值:6 ]3 m% l+ p; X# V/ {
1 z# e5 O; Q5 X9 s. R! |, k
如有一个对象:  t+ b" O3 N/ g
  1. { a: [ 1, 2, 3 ] }
复制代码

5 q! k1 \: S4 ]  @5 X- r
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
5 b) g! I# F* M# w5 K
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
* K2 d; Q! [7 w+ ?
1 v7 O- J; i, _1 F9 @
6)  $size9 N$ J/ o7 o  z; ^" P* c2 r& q

1 Y, w7 s) B7 s' ]$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:; z7 k2 H4 @$ \
. o7 `' C2 n3 W# ^6 }. R2 b8 c
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
7 G9 k# O; R4 f6 r9 h8 ]! U
官网上说不能用来匹配一个范围内的元素,如果想找$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.

& b6 j: Z. v3 n' Z" Q: F
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回1 T$ x$ v: t1 I2 x% S9 u& A! k1 O
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

9 W+ G$ O- n3 x# V
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string* w! A: S: v: K; B3 g3 ?9 d
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

( b! w. L: I( }" S( X& q
9)正则表达式9 Y+ R/ U" \$ E7 v- y

4 ?) E) ^# d9 F# D8 m& F- emongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
7 Q( j" C: o! L) }" C4 f+ U  h( O
10)  查询数据内的值
' a0 S; J6 q1 ~* R8 C. V0 U* t# S$ o8 u* ~3 J( t9 |2 Y, `3 o
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
/ [* O4 y- O5 w
11) $elemMatch( r5 q  j! _' n2 x! s* y
' V: }% s/ i4 X  d0 T# g) N
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    $ D& n. p5 Y9 f0 \# F+ ]
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    : l* G! R, K- x) e# P2 Z+ p3 J
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    9 e- `4 X# h$ E# S
  4. }
复制代码
3 n2 [$ L! Q4 g) H& ^
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
- j9 Z) F* l5 G% M: ~' D/ W
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 0 g9 }: h2 K: i! i# P9 D# ~
& o( B9 [, x! i. n4 X" S2 S* J
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
3 v0 ]8 z: L+ _2 K2 r$ u6 S
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

! O* R* }3 N3 Q4 R: [" ]+ j$ P! f
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

: S4 d& u( k2 m( K; R
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

6 Y, G- P) R5 l* l% O5 I
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
8 V) b' B% j' s) V; h
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

1 R6 @1 ^. G$ A' @
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    2 w  h$ t- f1 _6 N6 W* K: s
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

/ w. I9 C) g( E' y% m, Q4 [
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
, U( E3 L) G1 \. _# q! t  p9 v4 v/ e$ _) L) R
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
1 t  ]$ n, w+ s) C! \1 v& I+ D1 \5 {$ v
: C  `" C! ]: E& J- g4 {7 g$ I7 ahttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
0 T1 N  `8 ?: E$ R) `8 J
+ v7 ~" b$ e4 j. r' M3 D2 A版本二:
! i4 I/ |  F# |+ G% T5 [
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
: S6 g  o( D" F0 ?1 g2 u
  1. use admin
复制代码

7 a" [! k% b: ~
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
7 U/ e. D5 {* p  A: d
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

6 |4 S& h1 B5 P9 f
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
4 Y" _9 Y! R  I! Q
         5. #删除用户
  1.           db.removeUser('name')
复制代码

" b) \4 G8 T: b9 Z
         6. #查看所有用户
  1.           show users
复制代码
/ ?* B% Z0 V& z
         7. #查看所有数据库
  1.           show dbs
复制代码

" |7 `; C+ i2 N- d: i6 q
         8. #查看所有的collection
  1.           show collections
复制代码

5 T! n  x7 k% _- z! \
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
) q) C, I! b' z+ C; i( D6 U. I) ^* t
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
: |+ }9 e) e2 f. L! W
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

4 n; T+ i2 b. O) c
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

, q9 _7 G+ a. k
        13. #查看profiling
  1.           show profile
复制代码

: r; h; \" z- `$ D% U/ X- {" D/ t: O
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
6 _2 {2 ~0 C" h9 [7 L: R* e
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

% O& H! ?* n1 _" s' o
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

1 x1 x: n, t- A' t
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

8 B% @6 u/ p! y( f& O' d
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
; f0 l: v$ J" y0 K: k! Y/ ^
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
) z/ g3 s, \$ q
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
: D! I% g! X+ V
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
# h! ~0 j' G; {
   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()
0 H1 O; U- r6 j% @1 R
6.  高级查询
条件操作符
( Y9 }: F7 X$ l, @! Q1 J
  1. $gt : > 0 f: Q- u+ x& R0 B$ {$ W+ Z
  2. $lt : <
    " T# t4 Q; L) M- l* r
  3. $gte: >= & O* \7 ~2 j3 d: L# G
  4. $lte: <=
    , m( C. W  D  q4 Z! {# L. M, h* s
  5. $ne : !=、<> / h5 a2 t' g- |
  6. $in : in
    & i/ c. ]3 v  u& c
  7. $nin: not in 0 l. G2 i9 o: l1 F( O4 F: p
  8. $all: all 4 J! E! Z7 L0 a6 K- a
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

4 k; h, V( P. o$ I1 b& B7 j" B
" \  V; l2 m# ^" I$ L$ ]* w7 \查询 name <> "bruce" and age >= 18 的数据 1 A" H2 q* I" O
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

/ S% N3 \& h2 K' w$ Y+ W2 y2 W6 c' n8 s8 A& f
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
1 ]  U7 ]- }! ]. u* t" B$ ~
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

2 I+ s$ g# O* k' X2 X5 T! @7 T! K; n& V3 f. k4 ?
查询 age in (20,22,24,26) 的数据 ! s9 E+ A9 i6 V$ M
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
0 Z- W; g4 r' S
' z; T' f: t7 X& ~1 ~
查询 age取模10等于0 的数据
6 l) D' K- t( c/ h
  1. db.users.find('this.age % 10 == 0');
复制代码

9 ?! x( I0 N1 O或者
5 i" A0 z0 K/ q0 a" f: w
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

5 o+ Z( p5 h/ N) S) B' G, o
2 S$ A6 j" \' r! S匹配所有
7 |8 ~; g6 z7 Z' m. N, F  m3 P3 B
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% {2 ?: S* ]4 O: `8 ^
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } 4 e" j. Q  w8 ~: _$ V6 M
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
' x$ X# W+ w0 R
2 V1 X4 @  a6 {1 ~' x$ Y查询不匹配name=B*带头的记录
$ b: h. t7 `/ d; U
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

* t$ n/ U$ s1 C5 ~查询 age取模10不等于0 的数据
6 {: e  A. m1 |; ~7 I) z/ @
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

3 ~& s6 X- x* `, w( k9 S
* T% y/ ?7 w. Z5 N4 Q) Y3 Z* s0 V#返回部分字段 / u0 v0 x7 ]! n: W
选择返回age和_id字段(_id字段总是会被返回) * ^7 K  M) _- `
  1. db.users.find({}, {age:1}); ; T" D- l) ?" ^. R
  2. db.users.find({}, {age:3});
    . g6 o5 g3 J0 u% Q
  3. db.users.find({}, {age:true});
      x/ I1 b8 c! @& V2 w2 L
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
8 q) _, A/ i' s0 R1 k- D
0为false, 非0为true
; X( X4 e3 |& E. q! T4 ~7 b7 v: L' Q( c5 q& \* W
选择返回age、address和_id字段 $ D. p  p4 h' E8 C- n
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

7 |% X" w4 J8 A3 x! P$ w: Z1 f0 @& U
5 Z5 i$ N+ a$ c% W' H1 S排除返回age、address和_id字段
" Q! G% p9 `+ h& W
  1. db.users.find({}, {age:0, address:false}); 3 @7 F' n+ f/ x: M* j
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
* ^) f) ?6 \! \8 U9 L- [% S2 n

( _0 w7 m# p/ g% J( G& @( A/ b  ?数组元素个数判断
/ J6 ^/ d9 x! E4 a, j6 _3 E6 m( n对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 * ~4 C* f' m& C: w1 O. j4 t
匹配db.users.find({favorite_number: {$size: 3}}); / v' h. _0 w+ F& S4 T- Q
不匹配db.users.find({favorite_number: {$size: 2}});
: [( F% H' o: B$ D- S# u7 R- n
6 q6 ?8 G9 G6 K  L$exists判断字段是否存在 ! H' j% L/ v! `$ b
查询所有存在name字段的记录 & a, Q, }4 ]& b
  1. db.users.find({name: {$exists: true}});
复制代码
* }" T2 T# j7 c
查询所有不存在phone字段的记录   w3 A3 {/ e1 q  Y! `3 D
  1. db.users.find({phone: {$exists: false}});
复制代码

/ C  J) b5 E( k. h% c" l
- F# D- @7 H; d' W% [$type判断字段类型 / n$ `& f9 h; j
查询所有name字段是字符类型的
( Y) c+ i6 I& ]
  1. db.users.find({name: {$type: 2}});
    2 e; W; \! i0 e  k0 b  \: w
复制代码
& T0 X4 e4 s) T* m( B
查询所有age字段是整型的 % Y7 E( B6 z$ Y1 G, h: S& t
  1. db.users.find({age: {$type: 16}});
    ( @3 e" Y3 ~) S
复制代码

2 L1 T* B9 M$ @+ ?5 p! \对于字符字段,可以使用正则表达式 - ~. _6 U; a. }& G8 e; \  C
查询以字母b或者B带头的所有记录   V0 Z4 Q6 S: e# a
  1. db.users.find({name: /^b.*/i}); ! n6 p& Y( i; U( q
复制代码

/ _, N4 `+ E8 D: n, M* x& C$elemMatch(1.3.1及以上版本)
9 s7 W: @! f8 x为数组的字段中匹配其中某个元素 ! T, h/ Y- u0 Y3 O* s- s' G8 H

  R1 r# Y3 C( I* N8 o: _6 kJavascript查询和$where查询 , E9 f  }0 S2 u/ P
查询 age > 18 的记录,以下查询都一样 & W: a  G$ C9 ~: @) O9 M4 l) D
  1. db.users.find({age: {$gt: 18}});
    9 @0 W, X) Y! d
  2. db.users.find({$where: "this.age > 18"});
    4 E' t$ m1 T! Q* J' Z/ Y) b" {
  3. db.users.find("this.age > 18");
    7 O  R$ C# h0 u) z6 m9 G
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
9 Y$ _5 U/ I! F+ w- O' y' I

+ ?' ]/ ~4 N5 ^排序sort()
( p/ J6 A+ L  Q0 T/ w以年龄升序asc # r8 _% j. h. R) W. o" g$ ]
  1. db.users.find().sort({age: 1});
    ) ~* E9 z4 `# P9 b( d
复制代码
6 u/ S/ ?  c6 q( E6 M
以年龄降序desc
) S3 e  E: Y- E$ o- Y! T' {8 e
  1. db.users.find().sort({age: -1});
    ) t& U+ ~$ m$ E- B, p8 N
复制代码
7 u4 h+ \. ~1 b* F7 @1 ]8 V! P  A
限制返回记录数量limit() 5 b9 R! h6 Q5 S' Z9 x2 ~" z; s
返回5条记录
$ c3 b8 S" ]8 ~: e; Z! s
  1. db.users.find().limit(5); 2 r4 h/ V( n7 q# `
复制代码

: f+ K! [& \* `9 w1 T& Q返回3条记录并打印信息 / S5 U: f8 d$ _. y. G! q7 z) a! J
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); ) L% i' x6 y3 h: H8 M8 G  G9 j
复制代码

! U7 f9 {0 G# E' y; |结果 $ J0 y4 h6 \, }' U' W. O9 P6 R
  1. my age is 18 9 J8 g) ^& {" E0 K
  2. my age is 19
    & e% \3 U: l% [, f) O+ \
  3. my age is 20
复制代码
( ^: S  B# T6 Z! e: g

# e0 {9 j$ W0 h# x" Z- S  L限制返回记录的开始点skip() # }. I4 O2 k% U3 z  `/ t
从第3条记录开始,返回5条记录(limit 3, 5) / i5 }2 ^! j0 ~
  1. db.users.find().skip(3).limit(5);
    . _* h. O; D, X! _
复制代码
& y! _; h' ~9 Q4 d1 w- j9 y4 B) H2 l! b9 L
查询记录条数count()
3 X( |. Q* a) d, odb.users.find().count(); 2 r" @! Q, L& F1 A. N! Z
db.users.find({age:18}).count();
, U0 ~2 C  U( O& X% i6 h以下返回的不是5,而是user表中所有的记录数量 4 y, n1 x, v7 q6 |
db.users.find().skip(10).limit(5).count(); ( |! S4 b: x& T2 ?: f& h4 e- t
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) ) c8 w2 N' m, j' ~' M
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
! |4 d5 r2 _$ g3 }; A! X! `

4 G9 E7 v9 j" Z9 z5 V分组group() 8 [9 l0 M' C2 a2 \9 U& f& X9 R
假设test表只有以下一条数据 3 ]( q  g$ E( f. E; q
  1. { domain: "www.mongodb.org"
    0 F" ^/ K1 l: h
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    % i( Z( [, d/ H) p
  3. , response_time: 0.05
      i5 W* d  b% T5 P
  4. , http_action: "GET /display/DOCS/Aggregation"
    ! ]- i, M5 G8 K& o
  5. }
复制代码

% U6 U5 d% F7 n- o使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
) z6 @+ Y8 G" o0 `8 v
  1. db.test.group(
    ( s$ d; t2 p* b2 k( k' V) a* n/ Z
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} ' ^. t( |0 H5 P# `2 ~2 q3 y
  3. , key: {http_action: true}
      X# _( G+ z0 z2 N5 ~- j3 G, X4 W
  4. , initial: {count: 0, total_time:0}   R, d8 d( I7 ?/ A7 p
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    # R2 e8 B+ ^! t8 t) [% d
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } 8 J3 X4 a! O" j5 w, L6 H- [  P
  7. } );
    , S# N/ \0 `  m  V$ W$ W
  8. % K. ]2 l4 k9 x' N5 ]
  9. [
    ' Q1 O: F) o" z9 R6 z( b" ~/ L2 B
  10. { 9 f/ t  l) J0 C+ Y5 x
  11. "http_action" : "GET /display/DOCS/Aggregation", / L  o9 l5 a- |# [& J9 x
  12. "count" : 1, ( z5 f* n! N! M9 T% u3 ?
  13. "total_time" : 0.05,
    4 k- y. }  G0 w) s
  14. "avg_time" : 0.05 - |7 H* ~- l6 P1 J) N$ t1 o
  15. } + I! `( R9 O0 K! D7 k1 ^1 [7 y
  16. ]
复制代码
; R7 x- s# B# F3 N+ x

8 ^  n! [" c3 w0 j; X: ?" A
( x3 Z' L$ E* c. e  P& A6 D- ~3 ^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
    6 H& m; v/ {6 X
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
' P! X: |% N; ?% g1 A- Z* m
% g0 |/ A! U" V
, P: n% R4 _+ N% i$ K
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    " ], V$ ?. i5 [" J1 z
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

7 P  Z( |# j4 h+ k. @7 T9 V- I6 M2 N( m% Z9 D- f$ c" x! H
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

9 R3 @( O* S' F4 o' k( M
/ J# w. ?, D! e5 v( M# s5 Z
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

1 j$ x6 X8 |& e: C4 f0 Y
8 V. q, Y/ Q# t/ r6 T
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
, U- z( y* v8 J7 c& M1 k, Z. p5 Z
( C3 _! o  u" m
输出如:
  1.         4 ?+ _& _7 Y6 n* b; `
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
1 o. Z0 N1 Z+ y/ Q( A* ]5 g

) [9 y5 C7 w' h; f" p( i6 ^
( U2 G4 |  r  _+ a8 ~; f
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"! q5 P8 \. Z2 |+ F3 I
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    $ k. F3 P- f* e6 n0 f& Z
  3.        xmlns:context="http://www.springframework.org/schema/context"
    9 ]& u2 J$ j3 N
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    % s% c4 g& M; A
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    / R+ R# K; V6 q" O, ]
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    ( B! v0 }8 g7 L
  7.           http://www.springframework.org/schema/context" x: n% r: d/ U' t5 y/ S4 A0 m# I( _
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd* T- B, h$ t/ ^! o' `% _
  9.           http://www.springframework.org/schema/data/mongo
    ' o+ n7 z2 M; x
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    : U) ^  B! y! p6 K' ^- c  j1 z

  11. $ t* U' ?. c; ]+ Y8 J, i. {9 x
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    9 y/ ?' U( m) T. J) M
  13. . e8 P# i  I, K5 u/ c4 P
  14.     <!-- Default bean name is 'mongo' -->: P4 T' n( t+ O  B/ M* |3 O5 J
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />1 o; ~5 s7 [! d

  16. : c: N; k9 b) h) p9 `3 r
  17.     <mongo:db-factory id="mongoDbFactory"
    % u6 h) o8 }& q
  18.                   mongo-ref="mongo"
    1 F+ n2 E1 F. u4 y7 z: z5 D) ^
  19.                   dbname="mongotest" />: U+ ]3 V# X/ t% u; ?  Q: |

  20. 2 ^5 c- o1 {) n3 y4 J. \. B
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    1 n! a# k- z4 Y9 s1 J
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ! K0 [: z3 y7 n# s8 F) f! ?  I
  23.     </bean>
    ; Y! r9 y* \4 m# ~# U4 a6 V
  24. </beans>
复制代码

; A. x6 z5 }5 w

1 Y6 m  S8 Z' t- L6 M7 T, ?9 @
maxmin的测试
  1. @Test$ r" ]* L* Z5 b( n( k" y+ g- d
  2.     public void testMaxAndMinAge() throws Exception {$ Z! A; ^. w( v0 Q: v. h- i
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    % A9 e1 }' [( d; t3 H
  4.         Person result = mongoTemplate.findOne(q, Person.class);4 l* K8 A4 r$ K  k/ e0 R
  5.         log.info(result);, U) m- |$ U3 i

  6. * L8 T- U) T, j
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);6 C; ]  k: y/ t) I  I
  8.         result = mongoTemplate.findOne(q, Person.class);
    3 d# V7 C9 d3 s$ e' ?$ _- S7 \
  9.         log.info(result);% V: c9 [8 s2 W0 J; j0 H9 z  b
  10.     }
复制代码
2 e8 T' N3 r, ]/ d" O0 g
# o4 a* M/ F  r6 N9 T9 Z) U( T
distinct的测试:
  1. @Test3 U! z0 N, r# Z* l* u6 o+ P
  2.     public void testDistinct() throws Exception {( i; g2 d$ }% |, l
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    + Q+ z0 l0 G" }
  4.         for (Object o : result) {
    * J8 b0 r5 L7 ^
  5.             log.info(o);
    % U1 a: B3 Z1 o* ]  |6 \
  6.         }$ z7 i. H' b* I: ?

  7. 5 J( L0 B- J" N& \& d9 H
  8.         log.info("==================================================================");
    : g+ ?: b  e% x' H% q
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));* y; N' a+ q2 P4 e5 S2 g
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    : z8 o6 r7 s% g2 G* T+ w
  11.         for (Object o : result) {
    & o) @" [% ^' m& a
  12.             log.info(o);
    " b- S& I7 F0 q5 Q) [$ n
  13.         }) b3 p8 |+ ^! \2 c/ Y, L/ L
  14. , j# o: ?9 r- }7 k
  15.         log.info("==================================================================");
    . q! r( i( R4 Z5 Y5 C
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    " r' ]! ^3 v9 s  Z
  17.         for (Object o : result) {
    1 y9 w+ |" n9 e' I& }. ?
  18.             log.info(o);
    1 s1 M8 ^) o7 d  P  W, e( F, [
  19.         }0 L( E! l) n, _  ~) R
  20.     }
复制代码
6 L9 {  ?. t# G7 B& Z
" ^% J) n# A8 q: I5 K
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    9 J) g' T! J" S) k/ x3 s
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    ) S' Z1 i0 W* D/ h5 \
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789) u. ]1 m" P" l% z$ N) V, W( R
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654- L: v0 w8 `' P! W. n+ k
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni- C; a7 v5 f- }
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    " Y; @9 r, \( e( W$ o
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    . R! f! T: ~* e1 J
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================7 o% s  C2 q& A4 l% R- G
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567  b+ q7 P. |" ~; t" X- e
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    , H. E* M8 g, u% a
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789* Y0 E% C7 d) o6 s
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    * ^2 h& R" |+ d4 S- _3 `
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================- g7 e- D! p  s# W
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa) q5 a7 w9 @7 Z9 |8 s' ?
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    % f) i7 I# O7 O: U" y
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc3 }2 w; a& o& q, Q5 n  F+ Z
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www' }+ F0 k- f6 g% h$ `
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    3 O  x" q9 d' O+ i- A- A
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy( e6 Y2 k" J0 O# |0 m6 T: ]
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz# \6 Q/ p5 k. [+ W! F
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr& s6 P0 s' q6 K; L4 X
  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
复制代码

% J. u* {2 x$ F2 H! D! q. h' |9 t. K  s4 s
这里我要特别说明一下, 当使用了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等信息。

; I7 I+ i* b+ y+ I5 R
- `  s9 a7 U9 E: T6 Q+ Z% Y' {/ O  [' r
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 16:46 , Processed in 0.068201 second(s), 23 queries .

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