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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:; ?! N& r% y2 n: s; ~+ f/ H

4 P0 A, Q8 W* i$ W5 y3 u1 N1 ^1 ) . 大于,小于,大于或等于,小于或等于  _8 T- o7 z: s

8 S; h, l5 b' z! ~$gt:大于3 c2 [" c# g  K  A
$lt:小于
, G; K2 z5 |! I" N. j3 \$gte:大于或等于6 \) P8 F' q& \$ r& G& F/ Y3 k
$lte:小于或等于
0 |, V- F: k( D! j, r( z$ E" y( _, {  y; F3 N1 K
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    5 R) q9 J# V: a5 u; s4 e8 P* C, A" `
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    % l, w" I4 t" E0 h0 t1 Q. P+ N
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    / f5 b* e3 h8 a$ y" }6 H2 R
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

1 X. x3 U  S+ m! v
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    % k0 {1 H. ]) a: _" V
  2. db.things.find({j : {$gte: 4}});
复制代码

' |8 O% `. B* c2 y2 x. _
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

2 M+ ^# [% w' x6 l* d, X/ j% P4 |. h2 V3 r5 M) i* ^

4 _' |- [/ n! }3 q4 w( M
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

6 {9 A0 E; g" J9 E/ F, ^- E# X
3) in 和 not in ($in $nin)
6 y  n9 k1 O, g0 y' `, A: q
! o0 A0 I. I+ a- I语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
& g7 ~/ [& a# f$ c8 o2 n
例子:
  1. db.things.find({j:{$in: [2,4,6]}});# Q2 B: |% m, B
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
8 I7 H8 ~% R" _4 o( Z
. _5 ?. S+ G; o" g+ V
4) 取模运算$mod
9 \0 a) U' ^9 ]4 D! s9 D  e9 }' A  u/ n& ^+ {( Z( V! T$ T  k) C* n
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
0 E' ~2 P2 z& g5 @! m1 p; C
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

. j- }7 y# E9 K+ ^7 c" ?9 ]

$ _8 t1 R& S. q1 c" v5 N5)  $all! b+ o" a, c6 ~6 m
' b* a6 H9 P/ E4 `2 l3 S
$all和$in类似,但是他需要匹配条件内所有的值:
8 g6 {# t4 L$ g+ R2 ?
3 x- Q; q. V% H如有一个对象:
5 M5 t* B( h8 X+ @* y" q: S4 r0 j
  1. { a: [ 1, 2, 3 ] }
复制代码
  ~6 N9 K/ Q; D4 b
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
& i0 F, ]  Z" b3 N* D5 R; B+ J
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

1 Z( R* ^' ~6 s$ n0 Z
. W8 T0 f+ ]2 p! @) Z; e9 T( k% Q
6)  $size' e8 Q# {+ R  _1 B5 W

& w8 r- Z/ x$ G$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
# J! Z- t7 ]6 U9 @
* f+ n# O4 E  l6 [5 t下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
) R. S; R& ]: {1 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.
8 c7 h- u7 Z$ W5 w% o  g
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回0 }$ z6 v" P- ^
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
( D, |8 }; C& \1 k4 A$ [
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    # r" }0 k1 }8 p. @6 @; G
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
- b0 a2 v9 M- \4 y$ B1 R. K2 b
9)正则表达式" X  m1 h) Y& A7 T& D7 ^% y6 Z

2 h( B2 b! M' M& C0 @8 n9 L3 Umongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
( X  X7 h1 @( R9 A0 K
10)  查询数据内的值
. d- Y  S& _# k. E; T2 `
6 @8 T( O$ N# }4 u下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

) @+ x/ W: G& R; @
11) $elemMatch
: P+ W1 N# b0 o5 X
. \  _9 ]1 Q0 F( M, m  B如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    2 [% V7 S1 O& ?$ f9 z  F! z, o
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  # \' C7 k( g  A7 }& F
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    ( _9 I9 D6 o6 {6 W7 A3 ]+ {; s
  4. }
复制代码

: Y/ V$ O4 e( m( I) ]% X7 ]$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )' H3 l* C8 y" A0 M1 P' p! s2 p6 e/ |7 ~
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } + ]& S+ q/ S" x& G
: A3 r1 Z' W5 h2 s/ u
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

. U, P( C7 K) k; h, |
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

& |: _' y# g+ D
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
. ~' W; @' z* `0 |1 [
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
! q9 E2 I1 r* I
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
7 |& M* X1 }* ?
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
4 q& _) M- k2 z( X6 ^- ^
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    0 O; x6 k- H' y
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
) s, V/ o. i. i: o: {
mongodb还有很多函数可以用,如排序,统计等,请参考原文。& O" R; t" i: [7 j" Y1 X/ [9 M
! s/ w6 j( ]$ Z) b' [. e: X
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:" H) D* K% w* M/ p7 a7 `, O, \; I
. M2 b4 ~+ i. g$ ~; B: i) ?
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
- T4 B1 F& H+ x3 S# G' L0 x
6 n% _6 }) T' T4 ?版本二:7 b$ k2 U( D5 ?* c/ q
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
8 ]1 d. N5 S' G5 F7 n
  1. use admin
复制代码
- @7 E, a# ^5 ?  ]+ a- f0 w0 D( P
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
9 Q2 _" y7 R" F; e
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
; f+ J: V- A+ A0 U$ }0 p8 H: p
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

) Z* e8 Q! R( z' K
         5. #删除用户
  1.           db.removeUser('name')
复制代码
2 K& V2 q+ M) A" V2 |* ]/ `* a5 X
         6. #查看所有用户
  1.           show users
复制代码

  h  R3 A2 P5 d
         7. #查看所有数据库
  1.           show dbs
复制代码

& }3 T5 j9 T1 c$ x; W
         8. #查看所有的collection
  1.           show collections
复制代码

/ W- x( Q9 J# G: y7 k+ d' O+ j
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
2 k, u" H7 g' J+ k! Q4 [' ?& {
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
# ?7 r" A5 D: P3 t
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

: g- x+ a, H) [6 ]0 e4 Y
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
- C2 L; j  n( `4 L3 Q& {" E
        13. #查看profiling
  1.           show profile
复制代码

& @: R- c' v7 }5 `& L- A; N) O; a, \
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
2 F/ @) _+ N8 b% i3 j
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

8 D4 I2 \% Z2 i* ?1 J
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
9 m0 _# f7 g/ A2 ]
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
# M. S8 D" g0 u5 m
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
% Q# l1 i( o' x0 ~. k# L
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

9 n  p" P% O& M  b4 H
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
  [/ b* o! R) c. o8 o: }5 X
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

1 K1 s5 V9 H# @& w' D1 p0 p
   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()

+ B* _+ E/ i& U; u! S* t5 t5 q  ]* b
6.  高级查询
条件操作符 ) J( }, c3 P) L9 D" l! s- w
  1. $gt : > 3 A2 |& C9 A  q, E3 [
  2. $lt : <
    - `2 c/ O# P, V
  3. $gte: >= $ B% T5 G9 K- Y7 R9 i: J  E
  4. $lte: <= . L. K* Z( f" R. ~
  5. $ne : !=、<> # u1 p; H5 ]$ `" a3 k/ Y2 N
  6. $in : in
      D4 m8 h2 _; }3 C  k5 }
  7. $nin: not in
    & S6 t! d0 y. x5 {/ a' q
  8. $all: all
    3 B6 H; U, n: |. S" n# _, B6 E' n" W
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
/ k0 E1 \2 x, g

  d- |1 x0 L5 {7 Y5 ~8 n( o查询 name <> "bruce" and age >= 18 的数据
' S% h% a6 T3 |9 @/ `6 ^
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
8 s& C$ P# W) C6 X
9 C3 c2 f' v3 e* G6 I
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
+ ?! D. T0 y" ]7 Z" d
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
! W' l0 Y& U4 j% G$ A

3 k3 ^5 G! C- t3 k4 v1 T查询 age in (20,22,24,26) 的数据 ( i7 l7 Z' V+ ]8 A  W6 `$ g
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
% L( m) {' a3 s, P) d
4 W, R7 K" M% \! K2 P$ }
查询 age取模10等于0 的数据 0 ~- k9 b/ p, ]2 E: c& w6 i
  1. db.users.find('this.age % 10 == 0');
复制代码
. u, F5 b, y, F, B
或者 * Q* D4 }8 l2 j8 T5 r  ~. A/ B
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

8 U# ?' ]" n2 O. B8 q" _0 H* q0 B& W& L4 @* z" p4 w9 G, v
匹配所有
; j2 @: F# ?/ o6 J- Y
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
1 g/ `7 k1 @5 r, y! h  k
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
3 g+ ^3 Z- J- h& m: H- G可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } * L3 V3 u' w; ^( E# t& k
5 k" I& S2 [, @) Y$ ~
查询不匹配name=B*带头的记录 & r& t: v- {7 h/ |
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

( W1 r% \; O9 |! Q查询 age取模10不等于0 的数据 9 _' l* ]' e, N5 \* J
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

. A6 ~' f! G% T/ q4 C0 B5 H; ]+ [3 G4 l2 W
#返回部分字段
0 X& ]; H! t' M) h; x选择返回age和_id字段(_id字段总是会被返回)
; N7 @2 g3 u  ~
  1. db.users.find({}, {age:1});
    , ^5 b  e5 h2 \+ G7 R, O9 a: y
  2. db.users.find({}, {age:3}); 5 F6 X& i/ P. t/ t: e
  3. db.users.find({}, {age:true}); / B; }2 q8 B7 K  `9 I
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
! X# [. S7 m. C# c% D6 v8 _, w
0为false, 非0为true ' L8 o5 F! v5 I" c
; F: A0 N( \7 s8 l( N9 J8 V
选择返回age、address和_id字段
# ]  l$ a! \+ l8 M1 J; w
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

, a" u+ E% c3 g
4 I3 ~. l1 _% T  |3 R. S* y5 C排除返回age、address和_id字段
6 t+ W, b; w. E: b
  1. db.users.find({}, {age:0, address:false});
    6 n9 k( M0 }3 m7 t" p
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

3 m4 X# Y8 m$ X
* M2 E/ Y* l) |) X5 |- E. W, q数组元素个数判断 * ]9 @# R$ u3 c/ p
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 7 Z, u- d( H; @( w0 N8 ^. c
匹配db.users.find({favorite_number: {$size: 3}});
' p7 G/ a3 q9 N; m不匹配db.users.find({favorite_number: {$size: 2}});
. `. o7 n% S  j/ Z: d/ f& q8 U8 b+ d, S7 d+ m
$exists判断字段是否存在
9 R1 y3 V9 @% G% P6 S4 E查询所有存在name字段的记录 . `6 r7 J+ `, @% s( W
  1. db.users.find({name: {$exists: true}});
复制代码
1 D8 P7 h* B4 W6 A( S* `
查询所有不存在phone字段的记录 7 g6 z- x! N& s, Q
  1. db.users.find({phone: {$exists: false}});
复制代码
( i) R2 E9 g: g! ^/ [; r. W; _
  z- R9 K1 b2 u+ T1 }4 _. X
$type判断字段类型 5 k/ M5 l" L; G7 P' U( G  t) Y. L
查询所有name字段是字符类型的 4 _6 Z& q" P7 I5 s4 H7 V
  1. db.users.find({name: {$type: 2}});
      u- n/ }& l$ T4 ]% E
复制代码

9 s& a# L* g1 e% {查询所有age字段是整型的
  F  m1 t2 W# A6 M$ U( {
  1. db.users.find({age: {$type: 16}});
    ( G& R) b: {& p
复制代码
# u1 L8 M/ h$ s5 t+ m& ]
对于字符字段,可以使用正则表达式 1 j" ^; ]8 q8 F, V/ q% l: Q, B4 B. [
查询以字母b或者B带头的所有记录
' Q6 [; O  p* \- G6 ^& s  `2 V5 i4 m; P
  1. db.users.find({name: /^b.*/i});
    8 ~, A4 n& i# h2 c, ^
复制代码
6 Q) i$ Z4 j) z; Z; {+ G
$elemMatch(1.3.1及以上版本)
  B) V! T7 [5 R" Z$ _0 p# ^& z; [; K( x为数组的字段中匹配其中某个元素
) k% s) e% z3 j6 x% m- d4 f1 g9 y! s" M6 ]% U- |  g
Javascript查询和$where查询 0 \" q. {" B. O
查询 age > 18 的记录,以下查询都一样 ' B% @; P+ G3 Q) Q+ z# \
  1. db.users.find({age: {$gt: 18}});
    . m  Q3 B; x' I8 R  b
  2. db.users.find({$where: "this.age > 18"});
    ' T) D& C! c* g2 h% D" W% `
  3. db.users.find("this.age > 18"); ) G  n. \6 s) J0 }6 I  o# c
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

' N3 {( Z+ C& G0 c, u# }
7 G  D: H. D  E/ u+ |2 n0 K排序sort() 7 O% ~9 V! O" f  r* K
以年龄升序asc . I: a' \- f, N& V! N
  1. db.users.find().sort({age: 1});
    / {7 P  N/ w# I- T. r0 O. l# G
复制代码

& B: |  E( I* o5 e以年龄降序desc
4 P4 B$ s. \% I/ {/ _/ Y' Q, c* p
  1. db.users.find().sort({age: -1});
    1 y5 w# i- g/ _5 c
复制代码

; {$ o# S+ d4 d) C, ?0 p限制返回记录数量limit() 7 t/ ~+ q: e0 H
返回5条记录
8 s% s0 f0 G! j( z/ M+ z: n
  1. db.users.find().limit(5);
    ' q; c/ w$ O- S$ `; Z+ W
复制代码

$ M0 ^7 {" K! u0 L' V$ ?5 Q% q/ Z: _: y返回3条记录并打印信息 0 _) e6 m& g% V& b# \, A
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 2 m$ E# V9 G: G$ t0 E
复制代码

; u; u6 {: o, C3 Y! N! t. L1 A结果 & D: a" b9 {" U% a7 u1 k; |5 j) v
  1. my age is 18 * C" n, R5 u- ]+ }
  2. my age is 19
    : x  [! o" K6 V  [) q& Z
  3. my age is 20
复制代码
' I. r; y6 z  F2 d
1 A8 X3 k6 G/ W1 ?& q
限制返回记录的开始点skip()
3 x  G6 w  M2 x4 @2 u从第3条记录开始,返回5条记录(limit 3, 5)
9 c) W$ Q3 p+ j! G; s2 d' G
  1. db.users.find().skip(3).limit(5); ) R- f+ K; d# @6 r7 ?6 C; g2 o
复制代码

0 I' {* O  m0 g2 f+ p4 Q5 H! T查询记录条数count() 9 K% y5 ^  E# x' H- L
db.users.find().count();
; I3 L3 r+ B' Mdb.users.find({age:18}).count(); * k7 P6 M' _/ J5 ]  q) z0 d
以下返回的不是5,而是user表中所有的记录数量 " M1 _1 F" m3 n8 W# ?7 i
db.users.find().skip(10).limit(5).count();
& Q; g- z; r6 I5 e3 _$ ?+ @如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
7 P+ k0 y! m8 d( M8 u
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

/ Z2 P3 b( a# `. H) w# B1 |1 [- B, _# {: I+ d% X; Q
分组group() # c6 U1 }  C! n3 ], P
假设test表只有以下一条数据 3 F# U0 R) [2 b, b# ^9 B
  1. { domain: "www.mongodb.org" 8 O8 F+ ^) c: W* }( X
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} 9 K/ }3 E  d5 B( M, g' `/ ]
  3. , response_time: 0.05 1 b1 \  z( X: M% S
  4. , http_action: "GET /display/DOCS/Aggregation" ' Q2 w5 N, {/ {) j) B; g
  5. }
复制代码

4 n: e: R* P  ]+ J使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
4 m3 o  e: S2 V$ {0 r
  1. db.test.group(
    ( B+ a- F8 Y. c+ Q
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    0 P! C- {6 Y9 `9 a6 J2 Y; S
  3. , key: {http_action: true} . O' r! W! v  x/ J9 n
  4. , initial: {count: 0, total_time:0} , }) g4 g6 D: z! {: n! V* ]( x$ E
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } , h, ~" F3 Z' Q0 V9 h
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ' B& [) a' I+ z% Q7 q) \6 o
  7. } );
    % ?8 X4 V0 a; i& T3 R
  8. 8 s) k, i5 j! C* ~9 ?# P3 K  e
  9. [
    / O2 H1 B" H! L8 X& V" h
  10. { ) u4 B. Q/ Y  A! K6 Y) W
  11. "http_action" : "GET /display/DOCS/Aggregation",   F; {& c. A. i/ R; T
  12. "count" : 1, " E: F; e- I9 U1 |4 h
  13. "total_time" : 0.05, 9 ~6 j( e# i9 e4 S0 Y) ~: T
  14. "avg_time" : 0.05
    8 n* q5 Y, i% I3 r( {/ v' \
  15. } & P5 M2 }8 a: N8 L: g6 C! W8 y( W
  16. ]
复制代码
& W+ Z, a4 b" `3 t) s
( `1 i8 l- S9 C8 ~8 q

' ^( h; h0 x0 [8 i) y( WMongoDB 高级聚合查询
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. G( ~8 u2 D( w& w" n
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

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

+ G8 f9 c' n! x" i4 Q+ c- G2 O/ r4 z) z7 M+ r5 `
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
/ F0 H: c' j. c4 a' E; z
0 S9 m) O. ^+ U0 N. [3 |% ?
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
8 F! F0 x/ C' H

5 H% K9 u) ?, w% [: p* S: ]4 F
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

4 @6 ?: |2 A2 \$ N; B1 [  T. K
, D% u7 A8 M: |5 V
输出如:
  1.         
    6 p1 Z9 I, \' w
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

& Z1 e! E, S( L. u( M4 k+ q/ ^0 e5 r7 \" Y% \& a( C$ n1 O
% e- X' M  D' M! Z  ?
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"7 E3 h+ w1 h% q1 H  K( t
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    7 T& H  B1 \6 z( Q2 P. [
  3.        xmlns:context="http://www.springframework.org/schema/context"
    7 n- ^# p/ `3 ?
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    9 W& _/ P( v3 W
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    0 N* B) g" @3 m: b9 C& v- H; d
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd; Z& @* i+ X6 C* w! z4 m
  7.           http://www.springframework.org/schema/context; L) n8 K3 @& @+ K7 ]9 n
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    9 _% Y2 H' ~3 \. E3 Z, k
  9.           http://www.springframework.org/schema/data/mongo
    2 n% v, h* G; P
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">4 ?: y" Z+ X) W7 v
  11. ) Q( u  t* N2 i4 A2 O
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    % E& g0 D4 U: N5 H; t: \

  13. : ]0 \! R0 F/ \) w3 P
  14.     <!-- Default bean name is 'mongo' -->
    9 l# z1 O' d- X- M$ j3 v5 `
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    7 a! ]( M4 @$ c% b/ @! `
  16. # `( O1 j8 i8 R
  17.     <mongo:db-factory id="mongoDbFactory". O& ~# v( P+ Q2 ?# D- j
  18.                   mongo-ref="mongo"
    + v4 B+ z% h. `% S0 _$ {3 N
  19.                   dbname="mongotest" />' d# C: e$ I7 ]3 |/ o

  20. + |" O2 J+ \* s7 Y$ j8 G5 x
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">7 c; D% v( k2 f9 g) I
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    $ Z/ V9 K  d' o4 l* o
  23.     </bean>9 D& Y* d1 S' }8 }
  24. </beans>
复制代码

  r+ c! y4 z1 t2 T" W# j
. j, y+ P/ n4 o8 z& x5 i
maxmin的测试
  1. @Test
    , K" x4 n9 x3 g0 k( V: f
  2.     public void testMaxAndMinAge() throws Exception {
    " P6 m* J- w2 [( T
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    ' h3 q4 y& v0 e1 }
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    * c6 t( F, }8 e8 R5 G
  5.         log.info(result);* [6 L/ J! p: g" h" H

  6. & V) F/ ?( n" D  u6 H! n+ P
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);; v3 Q3 ~" {* _' s
  8.         result = mongoTemplate.findOne(q, Person.class);
    ' d8 J! A9 ?8 U! t, B: F4 h: w
  9.         log.info(result);. x) _3 E0 Q( ]6 I' ~) Q- v8 l
  10.     }
复制代码
3 G0 q" o$ l( }$ f/ m

; D, y) ~. d" _0 F" ^
distinct的测试:
  1. @Test  w. E# W' M5 B& x% W
  2.     public void testDistinct() throws Exception {
    . a+ [6 e6 z8 x7 T& Q. w; m
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");+ n* e& R: a+ Y6 o! T( y  V9 k' `
  4.         for (Object o : result) {$ z. |: ?; m' S2 s4 \1 |
  5.             log.info(o);1 k4 A; ~+ _$ @5 ?( J7 }
  6.         }
    6 w; s) _; F8 z6 S" q/ X
  7. $ l1 ]( ^' `, u* w  }
  8.         log.info("==================================================================");
    7 t0 {" G6 }+ p7 e1 |
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));: ^; Z+ D% L8 b4 n# o1 h
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());3 _) D; x" X& _* ^% O; y6 X
  11.         for (Object o : result) {
    8 e7 v- _+ w0 p* K& I1 O! q% Y# _
  12.             log.info(o);
    9 p- q: c& a, a$ u" l8 A/ Z9 Y$ `0 L& Q) N
  13.         }" N5 P9 R5 Q! }) q9 j* V/ ?7 r

  14. ! G8 {: D  @3 f& x
  15.         log.info("==================================================================");% z3 \% {; @0 j7 ]: [! L0 q
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");3 q5 ^% q5 P$ ~! ?
  17.         for (Object o : result) {
    ; S7 o0 p, a3 h5 G. b
  18.             log.info(o);- W$ E1 C2 ]  \2 a
  19.         }
    ' S! f* r0 F! [
  20.     }
复制代码
" y6 l! f7 s( k( b2 i" v9 m

8 A, B- U7 V& b
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    - r3 k3 U/ a9 k  m; ^4 e* O* z
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    ! x2 l9 W! W- T  i
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789' h, I& V0 \+ `+ I1 Q
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    * F. z& B! E* }/ J5 A$ S3 p; L
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    ; R* |$ K% R9 ]9 h. N
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    4 m. R- D+ ~; z% ?7 S
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    & t% M0 |- ~. K5 ]% f- [- i
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    # a! [' e9 u( I
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 2345672 }& T: B1 ~5 d2 E, Y1 P
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 3456789 z  ^% m4 |3 q' v. {  m' t
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    0 ^6 Q  l, S, z, [* E
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    3 d" {% r3 H5 @# x) v& ^* J
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================6 ]' ~$ }4 u% Y* q0 D
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    * T) K4 o) _: r7 D
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb0 ?5 L8 f, i9 P) ^( ]
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    7 S' n7 i0 q2 n" b$ n9 h
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    7 A2 n: ^7 i! G! g6 E  V6 M
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx/ i. {6 B" `" Z
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy* d( g1 `" ^% z' Q2 T
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    7 Q) S7 o9 n! h& p( A; N! w' f
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    ! x/ v3 s7 A2 V, 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
复制代码

" H: y7 k9 P# `% s1 w  J; I5 ]
5 \4 G% U, e- ?' y& j9 }2 n7 G
这里我要特别说明一下, 当使用了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等信息。

2 N0 h% a+ N7 T; x4 p
8 Y( ?, }9 ?4 K* K% u
8 u$ b+ g0 V8 N4 q7 O; S  |# D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-7-27 14:21 , Processed in 0.139783 second(s), 22 queries .

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