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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
/ c" s8 E% a: q, k, T: T
* B5 q6 @. Y: d! K0 R# E1 ) . 大于,小于,大于或等于,小于或等于
/ d2 R/ j- V4 ~. l3 [8 z3 s* A6 o* Q
$gt:大于  z1 x/ \* O5 v+ S% X
$lt:小于
! a( @- W% `$ |. F1 ?- u$ u$gte:大于或等于) f. t5 o) x; U! y
$lte:小于或等于7 [) |: h1 _* `9 [1 b
" E9 V4 A9 Y1 a7 J
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    - |  U1 u0 B& \
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    $ e  S% H+ s$ ~# e4 t
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value. A( _4 A- F4 X0 J# H: X( I
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
% m8 L& _: e) @% m. P% V$ {) Q
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});: O. V7 U4 g+ W# j) b, m# x
  2. db.things.find({j : {$gte: 4}});
复制代码

' @/ |: @* m! e2 j# n+ G5 F/ q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

2 w3 [% X+ u0 F& Z% O, @+ T$ V8 [8 S- O1 ^6 r
+ i$ L; E( q6 x
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
5 g( p% i" y; x  m0 X8 {
3) in 和 not in ($in $nin). f9 i& I; p! x% I0 a; ?+ v
* `$ H3 N0 @. }+ }0 T' c; t
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

- V3 c+ J5 v- E5 z, X' ]
例子:
  1. db.things.find({j:{$in: [2,4,6]}});4 ]; p, \4 \3 @
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
* z* l* E9 U1 E1 U, t. c
& y$ a* {$ I+ ], _3 I
4) 取模运算$mod
4 i$ c/ G7 N) p6 |7 A/ b# ^" A- P1 A- `9 k: e, ]% ^
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
$ h, A, j* `- ~
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

9 \0 _5 C% M& B& C  T8 n1 x+ W/ Z
: [6 ^0 g  j* F: J. Z
5)  $all
3 E  A/ s6 r" N4 x) Z6 a, w  o8 V- O& E( {) b1 U( `
$all和$in类似,但是他需要匹配条件内所有的值:9 F$ A8 r8 S( r; d: U- S8 |9 H5 q
7 m, C/ R+ }+ x1 ?& Z7 T$ |
如有一个对象:! e$ g$ }4 a' E6 @9 |
  1. { a: [ 1, 2, 3 ] }
复制代码
  m  n" b# `/ j
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

6 @7 U8 x3 {$ ^0 ^5 U8 S
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

+ j6 G: H: A" P- |5 x' z. J
) B- n$ a3 {% G2 V3 i" u  Z6 T
6)  $size
" y1 e! t4 B2 P3 s! _# _% t- P0 E& Y& q, \4 \4 q* e
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:& i, a2 ^2 ?" g' o6 ?1 ~  I/ i
$ x5 j  ^1 m5 q. k
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
7 V7 X/ g, T# q, W
官网上说不能用来匹配一个范围内的元素,如果想找$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.

. Y8 S; ~5 X) n, P6 s
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回) x2 _) i  o) u' R) E! o
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

# s8 j! H2 a) K' `+ L4 [9 P
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    9 Y: x, m. M  M; L1 h1 n  ]  I9 [
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

' E. M$ u0 G# @# {/ I! d
9)正则表达式
5 V, Z! D6 Y% S& U3 a* D: w5 z# k1 i1 A) @/ p1 z+ n
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
. }3 E0 j2 t, f4 g
10)  查询数据内的值
) }2 O7 x# u( _& v) g
8 {7 u+ X) Z7 S) U* x0 z/ i下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
* s0 P9 I2 u' l+ f6 _% i
11) $elemMatch/ Q1 Q  j+ R" K4 v
/ Z0 X: M& P0 @7 ~% q8 R5 O6 K. g
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    - T& t, ]% x9 w6 A
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    4 z( U+ u4 {* c* _7 b  y* R
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]: x* ]7 J( b0 M. t
  4. }
复制代码

) P- r# w! R1 _& A0 D0 P2 W5 S$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
4 ~4 _' L' |* o3 \; ?
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } ' k8 U, Q: v+ g7 B& P" f% R/ l5 ?

: q& d+ k& J* H$ @# g  F12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
  E% b& h7 `5 N( l! C
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
0 ^, x- K+ A" K4 p7 |. w
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

! J8 V8 V# L+ j$ M$ I
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
% L3 W. i, s2 F# x$ V. E, i
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

6 R& U: M5 c- i+ i
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

7 V" F; p* n* J  y
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    / a0 o7 l0 s% ]" t7 h# k
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

" r  Q1 z  `% y( E; V6 \
mongodb还有很多函数可以用,如排序,统计等,请参考原文。% m# m9 P1 R" F0 P: e

/ c. s' h% p1 i4 Fmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
* w. Z  J/ n3 L2 m$ m; Z# M  D" G+ V
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
% A2 s+ A& Y' l' L4 i  O" T, a! @$ ^* m* \( g3 `+ A+ N$ d
版本二:
) |( W( {+ }; l' o( _
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

, F+ w) _8 ^) R: M( n
  1. use admin
复制代码

6 N" n0 C" D6 }% z
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

4 M  G! |, v0 {* ?; o
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

( r* r* }* ?3 J1 c( \
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
) u& I- [5 a0 S3 t! A
         5. #删除用户
  1.           db.removeUser('name')
复制代码

8 B8 K; A* E; @8 a5 `
         6. #查看所有用户
  1.           show users
复制代码
9 ~/ o1 ]$ r" g+ w+ R
         7. #查看所有数据库
  1.           show dbs
复制代码
* q4 O$ c9 O" z. ^& l' o- b) J% V5 J
         8. #查看所有的collection
  1.           show collections
复制代码

/ U: g$ q# z9 R/ [. D
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
" u9 m5 V4 b4 d4 r" C- t  n8 c. Z& ^
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

, c% ?/ U" u  t9 O
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

. s+ H/ {! X4 W- z/ r( T* s& d
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

* _! Q$ U4 W3 K$ x6 f: o
        13. #查看profiling
  1.           show profile
复制代码
5 F" i' }' j( b. K! J- F& a& A
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
6 ?; z% v+ @( V& T5 ~
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

# p3 V5 q2 t9 e; R  Y' j  `
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

& |! S0 z- n5 E. _+ ~$ S/ L
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
; ]/ ?5 q* q, u, v7 ~3 g" ^
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
) Q$ T3 Z5 B8 j( }$ [
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

1 n: L4 {) a. L+ a5 y* n1 ]
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

4 o" q4 z8 w3 _$ G, \. c: j: T
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

! U' i4 z9 x" D7 N. @
   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()

/ W8 [- _: R' d/ ^: [
6.  高级查询
条件操作符
: x. F1 H3 P" r8 O
  1. $gt : >
    # X) h6 \5 @& w) V
  2. $lt : <
    $ \( O5 o2 Z# @8 a( [
  3. $gte: >= * K- Z2 S0 C3 I) ~, Q0 {
  4. $lte: <= 6 \5 x! q/ p4 E! |* g
  5. $ne : !=、<>
    ; v4 r# F. J$ _
  6. $in : in 3 G& b( K  R: b5 T7 x( Y
  7. $nin: not in 9 n& ~7 H/ L/ a, |3 I+ T( b
  8. $all: all
    9 c; A  U% X/ s/ C
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

7 c6 L+ `9 x% e, z
" ~- F- @" G$ ~$ o查询 name <> "bruce" and age >= 18 的数据 ' X1 f5 h& k, R! T) Z
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

, R' ~) Z6 v3 Q4 I9 G6 O+ W; N7 e2 Y5 j
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
$ G* Q+ h0 g! z. N
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
- e% @1 K5 z5 P- b9 W, B

3 c- d  H! Z1 P# {  n) O& A" X+ [查询 age in (20,22,24,26) 的数据
  L% B$ y6 ?2 ]; X+ F
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
* t; n+ z; P' W8 ]! J& V6 ~8 k+ g( u; c

4 b0 ~7 r2 T9 S' X* [2 T7 W查询 age取模10等于0 的数据
/ c7 [2 k. U$ K
  1. db.users.find('this.age % 10 == 0');
复制代码

! w5 }6 P  F" }3 d3 L, `% G8 M或者
# E! k1 `% G7 J( `1 O! N* m! V+ N1 I# z
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
8 L  x) b- p6 T8 V3 \: t
. J% o  _/ ?8 z6 D- I
匹配所有 ' e) Z9 e% ?7 t6 x( D9 a
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
$ Q* V- m; d" R: A4 L  K
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
/ @9 I' i# _" N8 `4 y可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 3 _' w% k# I8 E8 S" d0 y) z

# O& _2 ^2 U2 W1 z查询不匹配name=B*带头的记录
/ h2 j; ?! v! Q& `! X. e
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

* }4 n* n# p+ t查询 age取模10不等于0 的数据
0 A0 d, I9 ?- M( Y
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

2 r) @0 F# `0 w# \5 N( [
2 t6 X' q) w0 H( T) o+ }#返回部分字段
7 U0 q0 Q+ e4 O. i. V; E3 G, A. q选择返回age和_id字段(_id字段总是会被返回) ' I6 g5 n: z5 N7 o3 ?
  1. db.users.find({}, {age:1});
    1 j) g! i8 y1 L4 F/ Z
  2. db.users.find({}, {age:3}); % `" {* o$ }/ }" v
  3. db.users.find({}, {age:true});
    ; ]7 @0 s- P8 V# ]
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
, Q& V. u0 g3 i; N. c$ e& O
0为false, 非0为true
  ~! @" [( v2 G& c! c0 |( z+ X) l5 x7 f/ \9 a7 b( v, x
选择返回age、address和_id字段
9 F2 T# \/ A, @6 _& u
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
% z* ?' b; |' I* Q6 Q+ I

% G* o+ y" b1 M# ^) n; M排除返回age、address和_id字段
; _4 G; ~- w2 m7 [/ a" Z& X9 Q- h; |
  1. db.users.find({}, {age:0, address:false}); * f4 `  ]7 t, u* ]# k4 X
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
6 Q2 Z4 J1 L2 H+ p
  e! M8 a) o7 g1 }1 i
数组元素个数判断
/ n  L% s& U& }对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
" H( v! Y  |+ m0 r+ }6 d匹配db.users.find({favorite_number: {$size: 3}}); ; e+ W0 s& U  [9 Q2 i
不匹配db.users.find({favorite_number: {$size: 2}}); 6 a: v% o) i$ {3 w
- @6 e0 l, e5 l8 M, j9 T4 P
$exists判断字段是否存在
% p, h9 c& ]5 S4 ?6 R查询所有存在name字段的记录 ! R8 \2 Y) e9 m& Z
  1. db.users.find({name: {$exists: true}});
复制代码

3 C4 |& ]- l) @查询所有不存在phone字段的记录 0 L& ]! h4 S/ `# u  }
  1. db.users.find({phone: {$exists: false}});
复制代码

1 O; [' T4 g5 P; j
# X: x. z9 ]! @# C; _$ l- z8 s$type判断字段类型 & x5 N' z2 c& P0 C% w
查询所有name字段是字符类型的
$ E* n% U% u) `  y
  1. db.users.find({name: {$type: 2}});
    0 M- J9 b" C: o8 f/ k: [: Q
复制代码
( t6 b- {" N; p- d0 q( y9 R! U, W
查询所有age字段是整型的 ; g2 [5 j/ }' T  A5 B4 j; }0 U
  1. db.users.find({age: {$type: 16}});
    $ m) J% ]( u0 F
复制代码
8 T' L( n' e( p+ a$ M8 l3 m6 Q
对于字符字段,可以使用正则表达式
; W7 s+ q& Z& b0 Y& v7 U查询以字母b或者B带头的所有记录
/ {2 I1 s0 K6 X( d2 S
  1. db.users.find({name: /^b.*/i}); * a; T% R: O7 P3 x! E) U1 k
复制代码
0 s" n) P* [4 b
$elemMatch(1.3.1及以上版本)
8 J! P  m' j' z" g( n. @! ^. f为数组的字段中匹配其中某个元素
0 u! E) e2 }5 @2 f6 ^" U) X1 m) F+ T1 }% [. K  c. ~" U
Javascript查询和$where查询
7 {& y! X  i  G# U- Q# v& X+ o查询 age > 18 的记录,以下查询都一样
: h% D& R/ {3 O' ]7 e! \7 J
  1. db.users.find({age: {$gt: 18}}); 9 N3 q1 f  e/ `2 K& H
  2. db.users.find({$where: "this.age > 18"}); ; u. {# z5 |1 Y( ~0 X; {5 n
  3. db.users.find("this.age > 18"); / B; U. J1 P2 z. ?
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

: W3 y+ @5 _5 l1 |2 Q" d
8 K; w$ i* M# [排序sort() ; M4 R* ?- E. S
以年龄升序asc ) n2 V0 e$ b5 t+ t3 `3 W7 O
  1. db.users.find().sort({age: 1});
    0 u3 W4 L) A1 j5 E) B
复制代码
8 z3 L6 Y5 p' s/ j9 `; \
以年龄降序desc & D" q: D$ B: L1 H4 h
  1. db.users.find().sort({age: -1});
    $ R: b$ I5 }2 R' w3 p1 j
复制代码
) j6 I' X, |* n: _( i
限制返回记录数量limit() # C; I( K2 J( s8 }, D
返回5条记录 9 |- }( I9 w( T! ^: r2 r
  1. db.users.find().limit(5); / A& k7 A& Y! K; K+ l7 L
复制代码
0 l4 m" S2 n- Z9 z; k
返回3条记录并打印信息 * Z: O6 \6 V4 M3 m/ @9 c$ T4 Z
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    + k, W8 s7 H8 e4 D* s
复制代码
* S) C9 K5 }& w& {' Q5 u3 i/ D
结果 - c+ P7 K6 O9 T6 E* W+ T1 \
  1. my age is 18 $ \1 s' \% ~: J' i4 I* \( h
  2. my age is 19
    , c- H; Z: d4 y
  3. my age is 20
复制代码
, c' x; ~2 U' \

( q, C1 K3 D, R& I/ X" V限制返回记录的开始点skip() 3 l8 G: {, ]( E. Y* O' @# S
从第3条记录开始,返回5条记录(limit 3, 5)
7 e$ S6 C5 t0 d' w1 x
  1. db.users.find().skip(3).limit(5);
    4 Z: {9 M' Z+ o: h4 h* e4 D& K5 h
复制代码
& O$ y/ `8 {4 P, ?5 ]9 [$ ^
查询记录条数count() : a0 q% T2 ?& S2 A# U4 f
db.users.find().count();
& T' T' n5 |6 q" cdb.users.find({age:18}).count(); # @' H! }6 Z$ B! p  b' Q. z
以下返回的不是5,而是user表中所有的记录数量 3 V* t+ A' @: `& L9 V/ ^
db.users.find().skip(10).limit(5).count();
3 j1 ~$ f( c4 `$ S: |. r  Q( ~如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
) ?7 V+ v- F, W  ~* ~; T
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

3 c) M# H) m. P! E3 B
# W6 b( e3 R6 U分组group() ! U1 J" O( i. [& {# z! w  M
假设test表只有以下一条数据
3 ?7 q) |6 ^- A) \
  1. { domain: "www.mongodb.org" . M1 q& O& u5 `  s
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    0 ~0 d. x& n( u, ^8 ]
  3. , response_time: 0.05
    5 ^2 k' S2 }+ x# e2 e( v* \: ]" E
  4. , http_action: "GET /display/DOCS/Aggregation" $ Q% Y9 B1 i' d
  5. }
复制代码

" u( \" {# [# R: j/ L2 I使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 1 L5 G5 q6 c; u0 l3 }  x$ l
  1. db.test.group(
    ' u' z/ h+ R' G" m% C
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    : l" H4 ]9 G/ c0 y5 P+ l
  3. , key: {http_action: true} " S' x+ T# r) U' d9 o
  4. , initial: {count: 0, total_time:0} : E# @5 i, [/ Q& C& r5 U
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } % Y/ r  G8 J2 l; y8 b1 E) ]# B$ Z' r
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    & Q4 h' u4 d; T) d; }! x
  7. } );
    ! P+ L& q% C/ @) o2 K" H; @  n7 ^
  8. & Q; a* _% `2 a0 Q! P
  9. [
    2 ]2 W8 A/ \* h& M3 e( g! A
  10. {
    & a( X& a5 a0 j$ {* @, |: B3 ]: h
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ( r+ i3 c4 L6 W) ?3 Y2 _! e: x6 O! T
  12. "count" : 1, , q& N+ A! K" {5 j$ e
  13. "total_time" : 0.05, , M  L. E& L* c' K4 m9 @9 O" O
  14. "avg_time" : 0.05 ! G: }' A% |" Q
  15. }
    ' E, T9 I, V6 @7 P( r+ C
  16. ]
复制代码

& G9 E3 p2 n3 g, U/ Z
$ s1 }# s( [( d6 V. N  M* Z! p* _
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
    1 B/ f6 ?2 A. q) Q- \1 O5 U0 K/ Z: p
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

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

* t2 Y5 W1 g7 Q# q. Y
, E; l' k4 S, z3 Z& @7 h# F
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

3 @! q2 @' B% {9 J" A$ ~8 I
0 e& p1 m$ W3 o' u
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
+ S4 K9 @. W  i, W9 V# c
6 r. E- u  ]; c& s3 d' J% Y
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
! X0 p+ L) z' N1 `6 ]/ n

( O. u( q/ N$ z  D8 f
输出如:
  1.         
    $ W; a+ L' N0 T( y9 @
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
) _. z! J! w5 }4 o4 m* A
4 i6 \& G" Y3 _

& h) ?7 n+ ~3 ~, h) l
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"% d6 \' i4 k9 {: X: f* w
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    , Y# Q7 }' a: F% G) N2 S
  3.        xmlns:context="http://www.springframework.org/schema/context", [/ d6 v; v. p# V( |! O
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    + Z, B4 W9 O" ~* g1 l
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans4 p+ u9 D6 V9 B& Z
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd, ~+ B1 b& k6 }% B$ P6 j3 I
  7.           http://www.springframework.org/schema/context
      J& V5 C0 B0 u
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd: B: V1 |; o) k) _5 t" e5 W7 l3 X" X
  9.           http://www.springframework.org/schema/data/mongo
    / ^% I# Z4 j7 Y2 r" V1 `5 s. T
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    5 x  B1 P& `! r$ V3 }" R+ Q/ N
  11. 7 t# C- H" d: {6 J
  12.     <context:property-placeholder location="classpath:mongo.properties" />( I; _. z9 ?* L

  13. $ w( r/ D6 O  q$ W  H, |
  14.     <!-- Default bean name is 'mongo' -->& c$ e# }& }, j6 S8 e' X, t
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />: B4 f8 Z% @% Q3 s4 ]
  16. & B: `: B. e, l& U$ r# j9 c7 V
  17.     <mongo:db-factory id="mongoDbFactory"
    4 k7 c$ W. F8 g' E: E
  18.                   mongo-ref="mongo"
    * j! T# D; o  b# e
  19.                   dbname="mongotest" />
    + h( R+ I8 Z0 P) V2 l# b4 n
  20. * T+ C9 V3 s2 F+ V. J
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">$ l7 G( g; w  l* r  h) [
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>7 S$ s- y: x8 A4 H
  23.     </bean>
    + J- F# e5 T6 x7 ?
  24. </beans>
复制代码

1 \3 ~0 _) c# d9 w" c4 l

  u1 _; m- ~8 u* y+ m% e  w, C' [$ R
maxmin的测试
  1. @Test$ f' `1 t$ _9 j7 D
  2.     public void testMaxAndMinAge() throws Exception {
    - R, Q1 u+ V) C9 \5 @
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    - s( O0 ]5 `: M' q7 X
  4.         Person result = mongoTemplate.findOne(q, Person.class);# Z, |. z+ N8 ]0 ?- z& v! a
  5.         log.info(result);1 h& U/ D! e6 ~& X+ F( }4 y
  6.   z8 C  u6 X$ M" ?7 G) e4 M
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);: \1 T; {. |4 m& n
  8.         result = mongoTemplate.findOne(q, Person.class);0 N4 h/ q- i) g' r: q8 _
  9.         log.info(result);/ _& M4 g- B9 Y; A5 j4 J5 ]
  10.     }
复制代码
9 L# b- K, I5 ?& I6 X8 j; _: @

- D% H/ ?9 T# [5 \  U/ e
distinct的测试:
  1. @Test
    : m" m/ H7 X. B/ |2 i
  2.     public void testDistinct() throws Exception {
    # j' n7 Z4 K" U3 W: A7 l" T
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ) Q" M# i- p  K! B! I2 O( P3 T/ t
  4.         for (Object o : result) {
    7 n& E* c" |! P' I) R$ A
  5.             log.info(o);
    6 t% E+ N. E- t5 m1 Z
  6.         }
    % K& p0 f$ Y" y- g+ d5 T
  7. # W% n# A$ `. `
  8.         log.info("==================================================================");  i* x1 d% e8 r% w% o4 r& Q9 Y
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));, P7 N! m0 i) l4 [. ]9 v8 @( [2 C
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());5 J+ p7 |$ k1 o7 e2 J6 y" M! `
  11.         for (Object o : result) {. G8 O2 H2 s( d
  12.             log.info(o);' g# N2 k2 U: c8 D6 c/ T) u
  13.         }
    ; a* @3 r, |. \6 r* o, @1 T

  14. : i/ r3 [# r# v# U6 y
  15.         log.info("==================================================================");5 \! E& I% E  i
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");( s+ `  ^1 i5 b6 u
  17.         for (Object o : result) {
    9 I- \* I0 U9 g5 Q/ @+ ~  J
  18.             log.info(o);
    ! n' P; D5 c! U2 {  ?7 B
  19.         }
    ' g" O" u+ O! e: P
  20.     }
复制代码

+ ?- t) R; \0 G2 b( I. O0 {& ^3 G. R' B- _( X, B9 e
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567" d6 M& @* I2 s8 I5 U  v  d4 s
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
      O3 W0 w' x& H$ A+ b( W
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567897 Q/ `( j% t/ \- ~7 J* C. P
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    6 c) `+ L# j5 T/ \4 O; T5 j
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    $ X, b. {, v% R! b" k* |7 ~. _( ?
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo! v1 \1 k8 q- a' ~" n
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456! i* I% e* m, V- d" Y/ a
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================7 ]0 L1 G4 Q! j
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567' C3 }0 J1 [( b% ^$ X( A) m
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    , y5 T; R: H8 Q
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789) o% M7 m- K  `2 {* x
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654, _4 k* d' m3 H& [" b0 _* q
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================7 y$ _9 s+ q$ m7 l8 b" Y; X. j& m  _4 ]
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    . h) j; s* I* p- i6 _$ ^
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb3 Q% @! L7 y7 Y4 o
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc8 [: R9 i& C  ~2 b7 s
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www& @3 h$ _0 f' `; C+ t% S  y
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx1 V! ^/ {: T) Q$ n
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy' m  i! P: A' p, Y" f1 J
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz2 p4 c& m% g' A/ O. j1 H- r8 e* S
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    & a: h7 K2 A5 i# \# O( g( e2 V( D
  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
复制代码

5 I$ O/ a- ^6 T: H5 G# q5 U) A' \0 j" X2 c4 r% H
这里我要特别说明一下, 当使用了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等信息。

; q+ E; i; j. t& X: A# P
. Y& P) J6 l" n& B& t3 H0 }* y: t) T8 @
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-20 23:49 , Processed in 0.065896 second(s), 22 queries .

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