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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
$ z0 w& I7 |* v) S) C+ Q5 |) K' q0 I. Y; U. g9 ?4 f5 l
1 ) . 大于,小于,大于或等于,小于或等于6 r4 E+ b3 q; K( q4 n" ^0 I
! f7 G# _3 {7 \; Y
$gt:大于; J! v2 t* l% C. D4 Z0 f
$lt:小于
6 f3 f- \' [3 q. B5 F3 g$gte:大于或等于
3 g) {+ u: G5 E# Z7 v$lte:小于或等于
: d' m' q) M' X  v7 x! e
& ~8 e% {$ J; U1 g例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value( e+ a; k! k% w; Z3 o/ Y: ]
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value4 }( Y& ^0 Z0 v* E/ ?
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value; c/ H0 X& o/ e5 L1 B
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

4 a5 m' S" \6 x9 O
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});0 j7 B; S' @. d+ a& B4 T4 b  k" G: |
  2. db.things.find({j : {$gte: 4}});
复制代码

6 Z( {7 s. M8 _' |) k
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
- J; z, m* ]  D9 }# z7 k- B( n
7 h5 F7 b7 {& u5 L1 W6 ~% G: m

* ^2 P8 y) R5 n8 F1 [
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
) F' K  U8 S6 s8 i; o
3) in 和 not in ($in $nin)
$ u/ r: D) ]( d4 k2 `. u: M; R  e% {
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

$ _0 R& x6 B; T; v
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    , K' x' q' x; X/ X
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
& o: C5 a  H, m" @5 _1 J8 \

( F+ p1 T9 M5 r$ f* A) X4) 取模运算$mod# [# J" G8 y4 h1 H( {0 A5 H! ]+ [

- N. l( o5 v$ U, C. N2 ?如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
" Q! q0 @# y, H
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

3 ~' c8 v) B; D' F

/ v& q% h* }* o4 y2 E, W5)  $all
8 s0 S& h6 B- a* o2 w9 W  _
9 b1 u9 O, h( A" z/ O) \- u, Y$all和$in类似,但是他需要匹配条件内所有的值:
* r5 p9 ]3 G9 \! R" ~
( `8 A. T8 q& j" F: s, L* ~如有一个对象:
, ]# R. e& G1 p+ J; f) j
  1. { a: [ 1, 2, 3 ] }
复制代码
# E1 d+ X3 e3 m
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

4 W, `+ g9 r7 U! O/ A$ _
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

: I& s: r: R5 b9 ?9 Z
  b; b' R: v) d& A! K" [
6)  $size
  d' U: _% ^/ ^  S" u) |8 _
9 U* V+ T6 D: l$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:8 Z  e3 V% D3 G; |6 e" N% {
, \6 ]/ t0 L6 F& A8 u7 `8 M( A4 F
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
1 w/ r/ ?& @, Y( M* B* @% _" _4 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.
$ @  [1 |  x4 {$ U8 ]
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回: U8 \- U1 [2 p6 w, f9 b
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
! q* e+ V2 h7 D) C# H9 @  l
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    ' S" Q, `  `+ }% l/ H
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
' g4 I4 o6 {% A. a* c* k
9)正则表达式
8 s' _, L8 B! B1 p* l7 Z% ^4 R  }, j' P0 W" W$ D. H- N+ d
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

' p8 f! q$ \* }( S9 f; o' f( v
10)  查询数据内的值6 _" O- a5 @* \6 j$ k' E+ d
" H$ W0 m. K* U, h' M
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

0 I1 M$ A5 [3 F7 Q& s
11) $elemMatch
" U% B6 a' `# B7 M0 t3 T+ Y' d' F& l( s, o& o8 W; V2 ]4 O, N$ J$ g
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) ) F$ c6 j: e7 H% p$ c+ Y9 Q
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  ) ?3 \) Y$ ~# n- L. i( z  I  ?1 F
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]5 o7 U5 L# k9 n+ x0 \0 R
  4. }
复制代码
3 `; G; i& S9 g! I
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
& b7 Q9 U3 i% D4 m, c
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
# @( M+ H( J& r$ w5 p( e! i3 U6 c. Q( V0 _4 ~2 Y
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

% H4 A8 Q2 S( z" l
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
# }' C7 W/ H# I. m& a# H
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
3 e) M4 |2 o: T+ _% f4 J
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

3 l# f- W) |/ J8 y. j
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
# F: a, R- \/ t2 x8 C6 M
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

# N6 E& t1 }( p3 g+ z2 o. x
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    ; ~1 }- n. t* b" _9 Y* g/ s
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

8 v& a6 E; n) I" Q. z
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
. [# Y- P' Z5 x/ Q$ l$ i+ [8 A, H' U) X* T& a* A) ^# k' v4 K
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:* U& a) I' ^; p0 d# |* `
" x0 y+ e+ N9 {! [, D
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions, ~, P$ ?! |. _, O

, D0 f% M, `9 \版本二:
6 b  N* Q/ d! U% S4 T
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
5 j# B- p- {8 p% f
  1. use admin
复制代码
1 V: @* g6 U, _3 Z3 t
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
. U5 _0 G4 b8 Q* ~0 Z2 M& c  w6 e
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
  Y! Y, N0 p* c/ T; |" @
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

. @* H0 q- P9 E4 i7 n. @1 L
         5. #删除用户
  1.           db.removeUser('name')
复制代码

: M# @4 X( p5 a
         6. #查看所有用户
  1.           show users
复制代码

, N; Q5 t% Y% ~/ y
         7. #查看所有数据库
  1.           show dbs
复制代码
4 J( u9 `* u5 f
         8. #查看所有的collection
  1.           show collections
复制代码

8 t* G9 Z; E# b5 x. Y
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
; m& W6 R! K7 z  A& P! |
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
; n$ p; \. }2 s) m/ o2 ]
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
8 P# d- c2 ]6 J7 p2 M& |, M" N
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

8 v, {6 D9 J3 m4 f! y8 P7 N2 p/ @
        13. #查看profiling
  1.           show profile
复制代码
6 @) `1 a" a6 B, j' W2 C, g5 C8 g
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
1 P- r. Z3 s  j. q6 D
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

1 z9 X* c% |6 X1 ]0 g
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

/ p# \/ R0 Z4 j) d+ M0 q+ K
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
2 S1 v: f9 c7 H) A0 |
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
" f( ]% w! J% q+ m
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
) m) M$ ?7 k/ i5 s7 o
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
5 T7 ^2 \% L6 @% h6 f/ D
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

! j  A" Y! ?0 `
   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()

% i. R: _* R, |2 ]: Q
6.  高级查询
条件操作符
! h! D% a7 I" C  A/ t
  1. $gt : > : d" Y& s; J7 c! }" B( Q. t
  2. $lt : < 6 t: x7 W+ |, ^4 ]  \: J
  3. $gte: >= : q- m; c  [. k( N* Y8 Q! F
  4. $lte: <=
    ( x& ]3 Z$ A9 g- j0 M' g
  5. $ne : !=、<> 2 S$ E1 t* {8 h% W! Z6 E0 T% \
  6. $in : in . U0 m6 n4 j2 G: b
  7. $nin: not in ) H2 B$ x* }: b! W5 S/ ^" q+ h0 x" ~
  8. $all: all
    9 Q+ i) R4 ]" _2 ^( t9 a& F
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

( O, h. h5 L, |2 ^
& g6 P4 a: o9 Q( w查询 name <> "bruce" and age >= 18 的数据
3 r+ Y& Q) I/ V' i+ m
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
  ]" p  D4 w$ m) C* o: U7 f  x2 _' X0 S$ B
' l& X( {) Y  D# V4 R
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
6 z9 i. E$ V2 T
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
. |3 U- F! r- q+ }* r
$ Z! W. j1 n# \- p  V
查询 age in (20,22,24,26) 的数据
6 J* z3 u% ]) u
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

# A; ~; L, O" [- a8 V5 U. |8 @" g  m
查询 age取模10等于0 的数据
6 d4 K- i2 q; r6 v% S3 O: U% Q
  1. db.users.find('this.age % 10 == 0');
复制代码

: ~9 A) K# p7 r$ I或者
9 y, `7 D0 z: k! ]+ g
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
6 P. G8 O  G) g' E, u
% g3 U1 E. I1 w; e- v; M
匹配所有 & b: E  i- d3 |& V& s
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

6 D$ F% g# o8 I可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } & M$ x. x0 `. I  R
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
+ v8 r( \9 R0 }) Z9 i  E1 B/ G& p4 Q, `7 D3 [% z
查询不匹配name=B*带头的记录
: M0 k) K. p5 F/ n
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
0 P/ Y9 H  d7 w& F1 C
查询 age取模10不等于0 的数据
0 H) ]4 G3 ]$ n- H1 F5 `$ q' g
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
6 J# N2 p7 Q6 Q+ C8 u% S/ W4 M2 r. _
0 b! t+ m  }. k7 f$ [( z4 ]  z
#返回部分字段 % }9 B- n/ c2 V" n
选择返回age和_id字段(_id字段总是会被返回)
+ P  ^/ \: U" ^- ], N% ^8 t  J2 n
  1. db.users.find({}, {age:1}); ( k$ U6 m  d. e4 T* A, }8 ^
  2. db.users.find({}, {age:3});   W+ W, I; |2 Z% V" [7 v
  3. db.users.find({}, {age:true}); 4 p% ^8 k1 Z# B1 k8 w4 Y( d4 y; [
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
( F0 u) x. x. Z; z6 X
0为false, 非0为true 8 J* f, S! A# z8 w# \5 x2 ]

  C& A! w/ t: M$ G+ W7 J选择返回age、address和_id字段 ! g) o& T, {6 g! Z6 D6 P
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
. o+ E% W8 d! W- s  h
  ^' m9 X% O9 p1 E  W/ q
排除返回age、address和_id字段
! a$ w* {5 @- S, C. |) E* r
  1. db.users.find({}, {age:0, address:false}); 3 \. e, Y5 M3 O! |* J% H
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
7 V) Y3 z' }4 E/ {
! U) P- S6 b! X+ K/ I( s
数组元素个数判断
: r, a$ J$ c9 `  f! G; w对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
$ J3 ~( p  v6 t7 f: w! u+ `. ~9 r; G匹配db.users.find({favorite_number: {$size: 3}});
, Z: n8 F! z2 z" X' O. v不匹配db.users.find({favorite_number: {$size: 2}}); ) Q( z4 J! P3 M7 a
. ^; T3 ~2 k: ~3 j9 D8 c7 b
$exists判断字段是否存在
& \. M# l# i! A5 P" D( t. ?查询所有存在name字段的记录 , i  B/ N' y- @4 H# V  ^
  1. db.users.find({name: {$exists: true}});
复制代码

. C. M+ K) z& S' Z% K: n4 X* M查询所有不存在phone字段的记录 7 Y0 S) [. ~: x6 s( T8 G
  1. db.users.find({phone: {$exists: false}});
复制代码

% `; M. g9 U! J( A1 I( M, }7 |' b- n) N6 |2 u3 s5 j4 B
$type判断字段类型
" K2 J; ^5 t& _- Y* I查询所有name字段是字符类型的
* ?8 W# Z: B: T4 p
  1. db.users.find({name: {$type: 2}});   i) a! N& o' R3 h, \6 _) s3 H+ W
复制代码

* i8 E, M, u! l, O; D3 \+ ~( ^0 b查询所有age字段是整型的 $ V! p0 b" k4 {) i* p3 ?. U
  1. db.users.find({age: {$type: 16}});
      u, V7 `0 X; ^8 B  X1 M5 f# b
复制代码
/ c3 ~! s9 w2 p
对于字符字段,可以使用正则表达式
" Z1 K- Q+ G/ T. `8 Q/ ^5 _5 r& X查询以字母b或者B带头的所有记录 , B+ A+ U9 p4 d9 f
  1. db.users.find({name: /^b.*/i});
    5 T4 c: ~* ^3 I  R  X$ U( {; Q) Q' j
复制代码
( Y! ]" ~/ O" T" t2 Q1 J3 _
$elemMatch(1.3.1及以上版本) ) V8 h& |/ V6 [2 }9 T7 c" S, `3 |) @
为数组的字段中匹配其中某个元素 / q/ }$ h+ |4 w$ r8 C7 B; c

1 B' ]( R% l: V- P( PJavascript查询和$where查询 9 j& k9 ?1 q8 ]0 U
查询 age > 18 的记录,以下查询都一样
/ T$ Q; L! `" v
  1. db.users.find({age: {$gt: 18}});
    - m2 ?4 H* G* q  y
  2. db.users.find({$where: "this.age > 18"});
    6 U% U- u6 X4 Y# ]
  3. db.users.find("this.age > 18"); # P3 b8 E9 c; H+ `* g$ o+ @+ w, q  J
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
- _/ f! V. q; D1 ?6 H% A8 n$ e1 K! ?
# E: x. O0 t% L
排序sort()
/ L5 P( L: n$ P+ o$ n- ?以年龄升序asc 5 |5 X# ]5 h- i4 V* z
  1. db.users.find().sort({age: 1});
    " O6 m! l, R  Y3 |8 Z
复制代码

9 g+ |" c) L4 r( h# R  |' O; [以年龄降序desc / u) E. Y5 p6 c% R# t6 F% A
  1. db.users.find().sort({age: -1}); " d1 ?" |! [" [' n3 \
复制代码

8 G2 I9 i9 z0 y  d  N限制返回记录数量limit() 8 Q! [, ]' J- \9 }% W
返回5条记录 " U( ~4 ?  M. E3 ~- l+ l8 `# J' s
  1. db.users.find().limit(5); & K+ A" \) T5 }, n! S4 G5 [3 {
复制代码

* J2 ?+ A" I* A- j4 |0 ^返回3条记录并打印信息
; T" W$ r. s! h' c" U  Y
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); * s8 v/ M! N' }/ @# {
复制代码
" w/ o+ I  N, d: t  y, h
结果
( S/ l: A( H. z# N$ J
  1. my age is 18
    6 y" i- ~8 b2 N: }' K* ^! P1 O
  2. my age is 19 + b! X0 I( s6 V
  3. my age is 20
复制代码
( u0 H) E) P- v% Q( N, O# h
' t* O, k- e# Y1 A* p1 d; m
限制返回记录的开始点skip() , }0 k: Y) v: ~# F$ Y
从第3条记录开始,返回5条记录(limit 3, 5)
: _4 w4 T  o% B2 F) F, Q
  1. db.users.find().skip(3).limit(5); 2 k; T. f& E$ m3 H+ R1 E1 W
复制代码

4 ?; N9 U2 x( x$ v. U# t查询记录条数count() 7 }; N8 A8 A0 z3 {1 O9 E% |8 J. o
db.users.find().count();
* Q1 m; e2 E$ ?" Gdb.users.find({age:18}).count(); / o7 s3 N+ l, u3 j+ T' g
以下返回的不是5,而是user表中所有的记录数量
3 q. ?0 I; V( kdb.users.find().skip(10).limit(5).count();
. {# y0 n( c' |. _如果要返回限制之后的记录数量,要使用count(true)或者count(非0) + X5 T8 N+ k9 C! i' C* V  J/ E0 C
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
1 a, s: c- _. s
9 A! O0 ^2 U+ u* U! N3 l+ q
分组group()
7 g  L  R5 }6 Y9 N$ {假设test表只有以下一条数据 : f' b; X; R: n1 T% x% k
  1. { domain: "www.mongodb.org"
    * Y. b: M" o% G4 C/ J
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} * G0 R/ z- E0 g# i: R0 ]7 F
  3. , response_time: 0.05
    ; X( h1 ]( r% j( M0 z
  4. , http_action: "GET /display/DOCS/Aggregation" # r+ v5 X# @& V- h' `- J# D8 T5 e
  5. }
复制代码

7 e- @0 L. l' ?( A使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
$ I9 `, D: B8 u( I- {6 h
  1. db.test.group( & Z9 G  j2 K8 L' C
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} 6 A1 S# j0 I0 p, n
  3. , key: {http_action: true} # H6 A3 N" z, z9 f8 e7 e1 Z9 ^
  4. , initial: {count: 0, total_time:0} 9 X3 l- s) l, |; C; ~; F  L5 b
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    , ]5 }* \" |1 s) I7 g3 }
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    8 p8 e+ A1 m/ m3 s; }
  7. } );
    $ S, `# p% P7 l6 ?  L& b8 g
  8. ! A8 g! @, w8 W; b9 L0 A/ ~$ B+ V9 K
  9. [
    0 f7 K$ Q! i- p" I+ U
  10. { ! j; A. P" z' ]; Q6 e# I
  11. "http_action" : "GET /display/DOCS/Aggregation",
    0 A! C5 z/ o* e# e5 u9 W
  12. "count" : 1, ; q/ D! W1 o! V  K* m# `# ~& d
  13. "total_time" : 0.05, # ~, X* E- A5 q" a# ]& c/ p
  14. "avg_time" : 0.05
    + h: |+ J2 c5 h4 j( V- D+ A4 I
  15. }
    $ C- h( F: k5 _" h
  16. ]
复制代码

% P- @& y) x  C. {
3 ?& X  M; I$ @/ p" G. R
6 n3 R# w, R: Q3 FMongoDB 高级聚合查询
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" j2 A1 [! [4 ^# E) E4 a
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

0 \( T6 u8 d; a7 H( y- @9 I2 o. W0 s; P+ U

$ r/ X0 {% U% C( {' D
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    - V( Z: D) R5 |5 K5 z! o  |
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

( r8 T" R5 t. B! i
) i0 W  C, l' N# R0 Q' B
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

- j, V0 Y0 @4 p/ K" v& |, r7 @8 K  j- |
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

4 \' _" S) A) E  I! _0 Y% D' {9 {9 s8 D$ p6 n
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

) Z/ u$ v4 g. u3 f/ _8 F
$ o6 \% v$ @! N( N
输出如:
  1.         
    / G4 [2 j* P. A+ n0 v; O
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
% v+ i) x1 T- x! z; ~5 G

- }% r0 i( |+ x* U2 d+ b
9 S" Q& |5 s0 d( g& t4 ?! T( N8 Z
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"5 [& N) g6 ?+ `& |
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/ E; S6 m( g- t2 O$ L
  3.        xmlns:context="http://www.springframework.org/schema/context"# A/ J6 f5 A" s: b0 ]
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"% l" Z. d* B% ~- S
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans; j% {9 g% s8 Y3 F" {0 ~" A6 Z
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    + X8 T/ f& i5 |) ?0 N+ O0 x0 s( `% K, ~
  7.           http://www.springframework.org/schema/context& e' X' U4 F# m* ]
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    : s7 b. V+ c3 J
  9.           http://www.springframework.org/schema/data/mongo3 K4 c( c' x, r) ]
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    : x  L0 @) @3 M8 a! u7 e
  11. & v$ G- l! X& a0 a/ h4 H1 Z7 f
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    $ _; l5 m* v* ?; c
  13. $ {  u7 G5 h. z, f% x
  14.     <!-- Default bean name is 'mongo' -->: W8 z. Q5 B0 A
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />0 y+ l( q9 L, `( ]! C
  16. 4 d' t, X5 ?4 g. P) v- E' E4 _
  17.     <mongo:db-factory id="mongoDbFactory"
    1 }; P8 {5 u, Y% o8 e; h
  18.                   mongo-ref="mongo"- _( b# }, v! `
  19.                   dbname="mongotest" />
    + E# e) J2 y; G% V

  20. $ |$ \1 b0 ]3 o+ r+ ^9 H/ L! X
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    ; C7 u/ s( l  ^/ T
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ; j1 S6 L/ C( A
  23.     </bean>+ t' ]& @6 ^4 T, j
  24. </beans>
复制代码
' z5 s' J) c% r& w1 u3 W

$ ?  |8 i# c, ?; k, m7 |3 L
maxmin的测试
  1. @Test
    " }" t+ g1 F6 n7 j7 y4 ~! e$ `7 b
  2.     public void testMaxAndMinAge() throws Exception {5 u+ u& K9 B6 {; M! [
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    6 W8 @* D. ]. G! A/ b
  4.         Person result = mongoTemplate.findOne(q, Person.class);* r+ X& Q, R! H: ?
  5.         log.info(result);6 x/ o* @) s) F7 w; j9 r8 A4 W
  6. ' ]$ V# Z* O; q
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);4 P( l  J9 y9 [
  8.         result = mongoTemplate.findOne(q, Person.class);
    * Q7 E' K" ]8 {. V* Q; [1 C
  9.         log.info(result);
    . A$ W& |! L0 T5 [4 O" I+ g
  10.     }
复制代码

) t2 X% x' B/ ]! @- [' f0 S0 Z: S4 l1 l" b" K# N
distinct的测试:
  1. @Test
    ) |! G% l* g) `, J9 P. j
  2.     public void testDistinct() throws Exception {
    , f: ]  T% ]  p0 l9 I
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");6 R5 t9 L% e6 n- Q0 {
  4.         for (Object o : result) {9 E3 q3 o7 Z: Q7 n* t/ k1 i8 v+ V* w
  5.             log.info(o);. a. F. u4 ]! j. ~5 X- B7 G
  6.         }" K+ {' W! t$ G. }

  7. 4 I& z8 [# l$ _( U4 Q  V
  8.         log.info("==================================================================");
    8 J- c1 S+ ~+ I0 C1 q3 F6 }
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    1 z9 k  M) ?& l& j+ H
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    * i; U. ^0 f% W: U: q) M
  11.         for (Object o : result) {1 Y4 H. x  u! l' Y; I
  12.             log.info(o);
    3 g( ?- J3 m: x9 R$ H$ G
  13.         }
    7 {- q# q7 Z; h; h7 X

  14. + l4 ?) O4 Y/ u$ P6 \
  15.         log.info("==================================================================");+ c" G. d$ N% W2 @5 d9 h# s( l
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    : Y7 [% k4 a8 I) W" X# d* }' ^
  17.         for (Object o : result) {
    ' w. O4 Q% ^. I6 O( A. |5 J! q( n
  18.             log.info(o);
    " I& V9 T0 C* Y% i& H1 T" S
  19.         }
    6 |0 h3 g5 j  c" X. H+ _" {8 g7 r3 m
  20.     }
复制代码
  y4 Y# X$ B! Q  V+ w' u4 _: R) J
0 o$ s4 B2 }: T. u
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    ) x, ]& Z9 v- C. Y! u: B% O
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    - G  j; R6 L9 l/ _8 H
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    - Q1 F) N2 J: c+ _1 D- Z
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    ' n1 P- C5 n; n; {
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni' y4 t, v3 x/ A7 L, P
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo' E6 e' \. ]. h) k, ]) ^
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    0 w: ~. A9 T- V1 A/ w
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    - Y6 ^' B3 l/ I. H' C! I! f
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 2345671 a. z, f  Y; S" n" I6 L
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678) P! e& Y  c/ X+ y0 G. ~9 E
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    * a6 _1 P4 J; O# g2 g
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    ' S" {! Y& |7 p
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================6 [( Z# z! ?/ b/ v4 `/ Y
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa  E8 q4 f* p& p
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    1 ^6 f+ e" s  C2 i, b) ], J
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    + m4 \) N2 Y( ~! l# m
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www' d. U. b4 A, q* x" W
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx$ u- b+ G+ o) I% f/ t5 v
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy0 ?/ B7 {% V7 T! w) V2 `3 M# x
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz8 i( }( K; L9 f6 \- T
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr* k! p4 ^$ ?5 e9 @* Y7 Y0 F
  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
复制代码

; w3 T7 K. x  r0 V; \/ S
7 z- Z$ x( s" @* b' K; ]$ a9 U
这里我要特别说明一下, 当使用了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等信息。
3 a9 e% Y" H1 W! ^* i8 \, O
/ l9 z9 Q2 [, U' p' W( ~; H

9 f* i& N/ \0 S6 D& F( c4 C! W  ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 15:13 , Processed in 0.102711 second(s), 22 queries .

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