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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:2 U3 |- h/ Y, K) p

  t0 t8 f4 c0 g; Y$ ?$ L, S6 s1 ) . 大于,小于,大于或等于,小于或等于
0 B, [$ B/ \, i. W* n8 ^2 K. ?: h$ N6 c. J% A
$gt:大于
5 `' z9 o+ T# o( s9 o! o$lt:小于
4 K5 m: h5 F9 ~9 _: i" j8 {$gte:大于或等于
2 y9 b4 x( A; F' |$lte:小于或等于
0 L2 g2 a5 F+ P% g* ?/ }' x; f1 \' j5 u$ G& T
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value/ M  B6 Q* D* D1 F8 j! ~8 o
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    + Q4 E4 M9 ^8 |
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    ! A- T1 \9 e9 ]
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
0 ~$ Q6 {4 m/ x8 h* z
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});" B# T- Y* i& r; \& }' Q7 ^
  2. db.things.find({j : {$gte: 4}});
复制代码

' v$ u( ], c# \2 ^$ f& q. Q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
; L6 O7 I6 P0 I* {1 b8 k) G
) J3 e3 g5 i- Q, ^( y

$ V; d" s8 [" H3 J
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

2 Y' Z1 c7 y7 Y* M
3) in 和 not in ($in $nin)6 E7 b5 b8 v1 x3 |1 a

3 h9 U& y0 `& w; F语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

! X2 y- V( l2 ?
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    & R7 r! P3 t# Q; Y2 d( X8 p
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

# R, D6 b1 f  D/ D
* }$ _3 x0 P7 V3 z4 L% @- Z
4) 取模运算$mod
; y  C' l( s' T% \0 P& ^
0 l6 n& c8 _1 o4 k, e6 Z/ p! q如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
/ u& X' ~: `; O) _1 j: c: |( A
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
, u0 @( t! k: [% ]9 U* F

+ d( ~9 O5 s3 ~% S2 L% d1 r* y1 N5)  $all
' U/ f9 F" J6 ?- }* Q7 u% N/ p( v- Z9 H0 q; Z! C
$all和$in类似,但是他需要匹配条件内所有的值:
1 a; C+ T1 ^$ O( @. k
5 P" C7 _/ u/ {$ I如有一个对象:) ^& p* X9 x. C5 q
  1. { a: [ 1, 2, 3 ] }
复制代码
2 l) o" q% P6 @& d; R& f
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
/ F) t: Q2 p+ T
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
& B6 ?. B! A3 O1 ]/ M
5 I) z3 m3 P2 {* r4 c! s
6)  $size
/ E- v7 ]- \" a  P9 f+ U$ D
- U4 O* C! J7 Y5 S" z" X8 x$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
- ~. K8 Z0 G; J/ @; |) M8 }2 [  v7 M$ _; m
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

0 l# J% I( M$ b6 ~% b
官网上说不能用来匹配一个范围内的元素,如果想找$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.
) j" M" {9 z/ E+ o* J( i% _9 V+ a
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回6 a% I% J1 Z* Q: g  {$ W
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
1 R! u( ]3 z3 E6 D/ |
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string! j% ~3 Y: ~0 Z8 x
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
. w) q* p8 U% D
9)正则表达式/ D4 T1 y7 g+ X3 c9 F

7 b: u9 ]3 Z: @# Gmongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
# D6 c# O9 q: q3 O' g. H, m- K9 ]
10)  查询数据内的值
1 Q$ S& M' F6 P0 ?
0 O3 v# H9 [! G下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
7 j! q7 q7 v6 `( b6 A  G$ N
11) $elemMatch
' k; ?6 B! J! U3 R. x  }9 v
# b" _9 C( O/ L如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) + y; P5 d4 E6 O
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    / k, ]6 O7 P9 J, p% I' x+ X: ]
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    5 y/ C$ M0 E4 n3 K
  4. }
复制代码

$ P" O# C2 a: o# V. R* |) g. X' V$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )5 T# y" M, C' A9 E4 ~
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
$ L' C" P& }, M; H* o1 z4 R5 z: F- h" c  _2 s
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

- g. [) g& n# W2 _
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
) ^$ D& J- p0 t" q6 ^
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
  t+ h1 O9 x( U7 i- g
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

! v* G, J5 G" T: ?) o9 [
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

! b9 A- S4 R" R) Z
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

& p7 t/ y; @, V% B( J
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );. e( _8 v' L  A
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

* }) g' l- o( z  ~) D
mongodb还有很多函数可以用,如排序,统计等,请参考原文。- }6 l- [( i$ F% ~3 F

' B. I% y. F) l4 ]mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
: [( c8 Q- B: O$ y: ]) D
8 W8 |0 F& c' c! R! G+ Ghttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions5 B& K6 s  Y1 G5 J) |: |" X4 v
3 B4 H8 g4 w0 v
版本二:1 d& }; c1 n0 M% o! Y3 D4 J0 |
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
' }+ ?! o+ [- Q! p2 d
  1. use admin
复制代码

1 B, A' y9 I" `
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

8 ~7 U$ x% e' g9 [
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
9 _2 R+ J- X; B8 ?# b2 F* W! v- X
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

; s% d: q' D' \3 R+ B7 R
         5. #删除用户
  1.           db.removeUser('name')
复制代码
9 @  i  c; a) Z, Q" y
         6. #查看所有用户
  1.           show users
复制代码
" m4 V3 ]9 ^7 w/ K) F- n5 a, i
         7. #查看所有数据库
  1.           show dbs
复制代码
) h9 `2 W$ A& j. H& h& D1 W4 F
         8. #查看所有的collection
  1.           show collections
复制代码

( P+ e1 [3 X5 d+ i/ f
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
  v, `# \5 Y4 |. ~! l) Y, b
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
1 j: {* ~* D& G2 ~! ?
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

1 E- m+ o* H! _1 }+ q2 `0 f
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

# o  W9 q3 A& k7 ]$ g' {
        13. #查看profiling
  1.           show profile
复制代码

  i6 m, Z8 C6 u% f
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

9 W( p: m9 o( e* T/ o
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

. |7 ]& K+ i0 R
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
" r* X$ w+ F! q7 _9 j; y
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

! F- `2 L/ s: d9 \
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
; W; _+ b# ]8 t, h
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
7 j5 b- D& K0 C" ?/ _# B! p
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
" |! m4 v  V" `0 A. }
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

3 @* W% {9 L( O
   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()
- x1 E" f  X! ?* Q; h$ a) f
6.  高级查询
条件操作符
' |; I( O9 E3 T4 s, m
  1. $gt : >
    ( L2 h  z$ {: M( \) F( T
  2. $lt : <
    ; k+ Z4 w' ]* j4 ^' r
  3. $gte: >=
    5 g8 F) @- h) @" C9 v/ Q
  4. $lte: <=
    ; V, S; N( N$ f: B* P5 u
  5. $ne : !=、<> 8 ~  l" v$ F/ v% T( S, B6 U
  6. $in : in 8 Y3 i0 s2 L! G; C% F  d2 V* q
  7. $nin: not in # r0 ^! e: W4 N6 t8 o5 E
  8. $all: all $ M) c0 {4 s; }" }5 |  V! g3 X
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

# X9 Y$ ~3 Q" v8 v% V/ ]6 X1 }4 G9 ?  A) [. f. c6 S- _: J4 Z. h
查询 name <> "bruce" and age >= 18 的数据
& z& V7 Z3 }7 U/ M6 n
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
4 {1 G& X1 W9 V

( x( d+ H6 M2 a9 k+ w5 F查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
0 h& z5 A6 Z- u2 M+ S+ d
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

. w' i; Z8 |6 D/ j( n" q, L1 F: S. C( y5 a# f: |; a+ I
查询 age in (20,22,24,26) 的数据
, ]* g! G6 j( l- z. j" o
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
* @3 H7 ]) ^* ^7 k5 X6 t& A& o! @

, B8 u( L( I8 U/ y查询 age取模10等于0 的数据
/ p- @0 Z: U# U. e9 |
  1. db.users.find('this.age % 10 == 0');
复制代码

$ p; {: k: r* `) X或者 0 Z( V0 B1 d4 u7 J4 d
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

6 ^% \3 O, R4 w5 S3 {! x; N
  c( U8 O; d" ^6 \" @* h, {匹配所有 0 n1 d! K, v8 S
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
: U0 i+ i* |! R1 J
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } 2 n1 p8 p3 k5 C; a
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
& x: W, O/ l! a0 Y
2 L8 Y4 t" e5 G5 Z8 K查询不匹配name=B*带头的记录
6 n6 A: L5 ?6 U. ~3 T
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

8 o/ K1 u% q& T& d' z查询 age取模10不等于0 的数据 8 z( I* S: T' J( y$ W; L. U1 p
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

! m" \# N! G$ O  y) J5 Q/ V# @' }5 @3 ^% g
#返回部分字段 $ E8 d" k5 y. Y% a
选择返回age和_id字段(_id字段总是会被返回)
8 j/ y/ N0 C$ i" L8 }- ]% G2 J
  1. db.users.find({}, {age:1}); " N" W* L' m+ t) I
  2. db.users.find({}, {age:3}); ' |# e' m3 ^8 N# }9 C- C5 w
  3. db.users.find({}, {age:true});
    # ]" C! l0 b8 Z, L
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
6 Y6 `& K$ q' Z( g# z
0为false, 非0为true
" V6 n5 z- G% R, j3 Z  b  r! l  X9 O! _8 r. q1 ?3 P! A1 K3 `  r2 i; c0 Q
选择返回age、address和_id字段
0 V! w3 \) G  @* T  W
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
3 K" M5 y/ A) h- S
8 F5 H; b' A2 a  _: n, j
排除返回age、address和_id字段
1 g, D/ z, L8 e! J
  1. db.users.find({}, {age:0, address:false}); : p' f  J; {7 K% k8 Y
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
7 [7 M6 G# F+ R5 \! L3 Z
! w3 d  t2 r) ?3 D! x3 H
数组元素个数判断
. Q) z  h- ~  {% x* {对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
+ ]( [: N& Y5 |% U* g匹配db.users.find({favorite_number: {$size: 3}});
) x9 ^2 i" ~( x5 `* C2 R不匹配db.users.find({favorite_number: {$size: 2}});
9 H  d* S$ I% r1 W( r; u! }
6 K8 r  u! g7 }% u2 F' }$exists判断字段是否存在 4 P9 P/ o: H3 \7 I
查询所有存在name字段的记录
1 U5 M9 D8 l' K6 P; {5 j
  1. db.users.find({name: {$exists: true}});
复制代码
1 O0 \" g- o  y( N! }
查询所有不存在phone字段的记录 * u/ }" A. ]. Z6 l$ B- i7 a/ [
  1. db.users.find({phone: {$exists: false}});
复制代码
  b# m* F+ L. c3 J9 r$ d
9 j+ i$ b1 `2 k+ c" p% `/ C$ E9 V" e
$type判断字段类型 3 h! {% h9 ~' z4 K1 S: I
查询所有name字段是字符类型的
  t2 R, J6 R/ s1 X7 U: o7 `9 X
  1. db.users.find({name: {$type: 2}});
    # w! U0 |' Z; `# a5 n
复制代码

3 l, q0 d! v% I& y) o查询所有age字段是整型的 * J  ?) P  H- I% \/ i; H
  1. db.users.find({age: {$type: 16}}); & u( {: N: i1 Q
复制代码
+ w3 U% I5 g9 W7 y# c) S$ M
对于字符字段,可以使用正则表达式
( m) [3 H" Y7 x- L% \  f* G查询以字母b或者B带头的所有记录
" ]* ?" T5 m" B2 [) `# a( U* t
  1. db.users.find({name: /^b.*/i}); $ y4 W1 v, N, B5 q- ~
复制代码

( J1 m; U+ m4 f4 e$elemMatch(1.3.1及以上版本) 2 ]1 a$ p; V+ }& M+ Q
为数组的字段中匹配其中某个元素
. ]2 y8 n. I- F$ y: n" C: S9 s; j6 P8 k* l" c
Javascript查询和$where查询 ; g7 P/ n1 E( R7 Z5 K  b
查询 age > 18 的记录,以下查询都一样
) o$ P9 Q, i! q+ v1 I
  1. db.users.find({age: {$gt: 18}});
    # s- P7 H8 ~5 z# a1 @& Z8 ?4 ]
  2. db.users.find({$where: "this.age > 18"});
    # c6 i& B, y8 T. |; t! Z6 x0 w
  3. db.users.find("this.age > 18");
    " B" z1 _% V- N0 n* ^
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
( M2 w$ L5 c  r& y. N
% G; K  }/ f; o+ x" l
排序sort()
) E' ~- K5 L% w以年龄升序asc 1 }( H" ]  y# x
  1. db.users.find().sort({age: 1});
      G$ A7 {4 n1 g* u
复制代码

, D* x8 ~) v$ c1 u以年龄降序desc : |8 s1 n( Q3 c. W. Q: T
  1. db.users.find().sort({age: -1});
    4 C' i3 D- c9 T" f# G  X
复制代码

3 p% j0 b* |' Z* X0 e. R5 m# ~$ K( e限制返回记录数量limit()
) ?- @  l1 |; p9 n2 T2 H返回5条记录
8 X" U7 r6 t- c: w3 b" \+ n2 X- {
  1. db.users.find().limit(5); 3 w  z  f* p3 {, u7 Y/ W$ j4 D
复制代码
$ c7 t2 k: P5 T3 [7 x7 ?$ S3 ~8 a* q
返回3条记录并打印信息
( x% r; C2 l2 x3 n7 _# R4 i% ?
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    * n% S7 _0 R, ~5 O- D
复制代码

+ {8 K5 E2 H3 {2 F  H  E结果 % r5 c- i' g7 K8 X$ s( Z
  1. my age is 18
    # E- @# s3 b  j5 y# C6 @
  2. my age is 19 ) p" h9 T0 ~# m% ?5 u2 L
  3. my age is 20
复制代码

2 Q; T. a* ]* @  O, g4 n* V  ^+ v
, V" @4 W+ L* i% T  ?; _限制返回记录的开始点skip()
& Z2 P$ ~: u; j7 X% I! M; G$ e' p从第3条记录开始,返回5条记录(limit 3, 5)
7 P3 i2 m/ M; B/ X" ?$ S( ]
  1. db.users.find().skip(3).limit(5);
    , s' Z6 d4 c& M1 C( T. T6 I
复制代码
0 E7 L% M; Z/ ~! e
查询记录条数count() ) v  I' C; V$ q
db.users.find().count();
% ]2 a" ]& y+ k1 Gdb.users.find({age:18}).count(); , E8 O! ]  z  A4 g/ M3 }
以下返回的不是5,而是user表中所有的记录数量
2 d2 @5 Q8 B" `; E4 tdb.users.find().skip(10).limit(5).count(); 0 r2 k& m2 y. f1 y
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
1 j: K9 r8 Q. ?  `! {8 `
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
# a* W" ]; H* W  w% S6 ]' r" G
5 B+ U. d8 M0 \
分组group()
3 ?0 |: \; ^- u0 h0 y假设test表只有以下一条数据 : F+ f1 B6 A# G' s5 l' M
  1. { domain: "www.mongodb.org"
    8 {& g5 s# h1 ?/ f
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ; ?" _7 r2 q# y: b  L
  3. , response_time: 0.05 4 O- E- |) J4 ?
  4. , http_action: "GET /display/DOCS/Aggregation"
    : y0 i" _/ i* F$ P# s8 X/ |
  5. }
复制代码

* l' t; r3 b* T& ^6 Z% L使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
0 b, A- @6 C" U3 n9 w$ L5 P) {
  1. db.test.group(
    ! a% H; `4 W0 R( Q
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} : @- V5 W* V5 p' t
  3. , key: {http_action: true} ! e0 v4 }' P6 j1 z
  4. , initial: {count: 0, total_time:0}
    ( L: }) L7 \) v' o
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    , |; d2 F8 ?2 `! a7 t% T% g+ s) B6 K7 n
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    5 w6 Y% b% P! a1 s& ]* \
  7. } );   Z0 v) r' {2 t1 u/ l9 U. H
  8. + y% ?2 E8 f" {; c
  9. [
    % F1 s* ?7 @# \, Y2 ]
  10. { 5 q% `7 V; }4 A
  11. "http_action" : "GET /display/DOCS/Aggregation", 2 W+ ^3 p" z( d' d$ w
  12. "count" : 1, * j: f9 k3 h& w
  13. "total_time" : 0.05,
    * h/ X4 ~& y9 N; ?' f8 W! k4 Y, i
  14. "avg_time" : 0.05
    8 |# f' P" A% A( ]1 p
  15. }
    1 f" E# F7 u7 j; a
  16. ]
复制代码

1 n! }# w. |+ M9 ?1 t5 l. y- W3 D: F
2 {1 A, J2 |4 d- T
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
    $ L2 y) p6 B2 G2 s
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
# w5 `8 X& ?- P' T

* u& B6 k1 L$ t

7 G' {' i9 v/ n; A* R* ^
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct1 B3 Z+ x( n9 a' G2 K/ B' e
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
2 i- ]) Q& D5 y7 G7 d; b
6 o  O  ^% t! N5 k1 s
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

! _! D+ C* g, z* \9 o4 p* @( `0 H1 y
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
, e  n/ w; W% `. C

+ ]# G" G) N- }
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
# p( K1 a- P. W, `9 g$ C0 R+ t
2 Y5 u% c6 f4 w$ U
输出如:
  1.         
    6 s7 J- e' W2 J: }* B6 _
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
7 o9 k& V6 i+ w8 X: |! N$ d* o/ q3 J

& n! x; M  o; x+ _4 L1 o! P: u  Q: `+ ]0 o1 n
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    ) e" \9 i( `, U9 s5 {
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    8 h1 F$ {* {2 K) v) d. @" k6 ?
  3.        xmlns:context="http://www.springframework.org/schema/context"3 D! x1 j- F& }3 r+ j6 I
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    $ z& T& b( }) ^8 \0 S  ^( j
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    . L) |8 y2 w! M
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    $ I2 J+ ]* s* B
  7.           http://www.springframework.org/schema/context0 Y7 k# r1 }* L+ ^( [! Q
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    9 T, S* s9 J1 K* n! w6 |
  9.           http://www.springframework.org/schema/data/mongo# g8 \) H6 D5 r9 F4 P; W7 F/ @1 X! N
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">* I+ N) T1 R0 v0 K" Z# V3 R
  11. % D' o- r. A$ g, F, |
  12.     <context:property-placeholder location="classpath:mongo.properties" />1 S; C5 q# L/ b6 ]# `* @

  13. 9 G' r3 H" X) l, f! {: x
  14.     <!-- Default bean name is 'mongo' -->( |: ?" a( q; j3 a( L
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    9 x+ B; P2 c" |3 k2 i

  16. ; O7 }& F! g* O
  17.     <mongo:db-factory id="mongoDbFactory"
    3 n- |6 j# J6 ]% L( r, T! e* q
  18.                   mongo-ref="mongo"" A) m6 D- g! `2 g( G; c) O6 o# w8 r
  19.                   dbname="mongotest" />
    + M' }5 A( n5 [5 H+ g/ Q

  20. 1 b# d/ O4 ]7 ?0 c# d
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">7 G9 S, C( L. r& a* G8 P
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    6 g" Y. ~! C9 Q3 A5 ?* s
  23.     </bean>
    ' y3 u. N8 a3 E2 Q6 [$ z! I
  24. </beans>
复制代码
! E# Q8 W& h9 B& _

3 X& F4 |; D; n* d; c: ]
maxmin的测试
  1. @Test1 d8 K+ f: ~3 p/ z9 A5 {8 G
  2.     public void testMaxAndMinAge() throws Exception {5 g8 i$ S7 l+ v( c& V+ e6 ]0 O- `
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);3 W) C5 ]3 ^( A8 j
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    4 W, u- @" Y, U( \9 c; \
  5.         log.info(result);
    2 v) x; P# x* d) P: l1 J

  6. 4 E9 m2 i: d* N5 }$ @; r
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ! \, c. P, u" p& m% F% u1 i
  8.         result = mongoTemplate.findOne(q, Person.class);* S, Q5 H' ?! V( B! k( b; ?' N
  9.         log.info(result);
    ' Y7 L! `1 \; _  T9 `5 z
  10.     }
复制代码

6 [  I) y- v7 u
2 ?+ _: @2 K2 J: n) t! g; v; _9 m
distinct的测试:
  1. @Test+ d# C$ C9 ^+ p6 a0 u
  2.     public void testDistinct() throws Exception {
    , e  ?$ X# a8 }* A# f8 `) c
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");1 s, g6 p- u$ Z+ x. F! L% n
  4.         for (Object o : result) {
    ( C* i' p" o: g9 ]
  5.             log.info(o);
    % q# T# E9 G# c) h2 c
  6.         }8 n0 U/ L" K! p; W' z0 X& ~+ E  k0 h
  7. % U. }. k* Z0 @  t
  8.         log.info("==================================================================");
    - C5 j! t- `+ k" B3 V5 {
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));2 q6 U/ |4 O9 \" f
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());5 P4 U# g7 h6 l
  11.         for (Object o : result) {
    : |* v; F/ L( r
  12.             log.info(o);
    2 K) R7 V: L# I$ Y4 l/ Q
  13.         }
    , C% j1 ?2 z) S& @
  14. 4 Q7 _# @9 k# N6 `9 T6 B
  15.         log.info("==================================================================");9 }- b& R3 z. d6 s
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    ( l' ~' f. J6 f/ F3 K+ r5 `9 D
  17.         for (Object o : result) {/ C3 L" O9 [- N) ]8 c3 _
  18.             log.info(o);( F2 L/ \6 S. b& ]6 M4 J3 T0 r6 |4 m
  19.         }, j5 u  N' Z) O6 l% i9 c
  20.     }
复制代码
( M  |& k1 f  B( X$ m9 W4 w7 n7 I! n" S

0 J. F3 j% y; j* V
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    4 T& t4 m. K/ N* R# x
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    9 O( ~/ c  g! ^; C
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    ' {, |/ H& S$ y5 H0 T
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    8 L* O- T1 P5 k
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni  N2 g8 R3 C# N9 B$ n% {9 i
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    ( P; Z; `8 _( |4 s& `- b
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456% c2 |- o4 y! z
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================2 T! T, O2 M; y5 R# I% o: X2 X' `
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    ! e- l4 x% B3 t, ~& c# ~8 \! t2 W' S
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678, t' m0 v7 b( i. R1 k  k
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789! `! o3 m! W8 N. {" I
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    $ H& V' T* H: F" _) |
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    ; }0 `5 p( W! d4 H5 J$ x' s8 f0 Y  e
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    5 q  j* F8 p: L
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb2 c0 y# e; v- H
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc  I/ C' e2 V7 m- f5 @
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    & q9 M( T5 U1 `
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx( L1 a2 b  O2 T7 H2 F
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy) z8 O( i% o- z. B$ q/ G4 T
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    ; ^' U% ~& S- V* L
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    % G. s" ^0 V1 c' e. n6 m# j% a
  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
复制代码

/ j2 q" ]; j2 S6 z" N5 M1 W! _8 S; W% }: `6 i! E; T) 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等信息。
. a( g, G8 h( Y( a4 z

; R* f! G' A' h% o& T, u! S
) j- X' M+ L5 {9 ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:02 , Processed in 0.144146 second(s), 22 queries .

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