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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
: Q1 k$ k$ B  j4 A% F% M- [3 G7 W/ Z3 @. `* K
1 ) . 大于,小于,大于或等于,小于或等于
% {- J6 R- @, ~; v) e% H( w, n6 j7 v+ a6 e- e) ]
$gt:大于
& x- W2 b6 z4 O" |$lt:小于
7 r9 U  ~# t- U( b1 z+ P% N$gte:大于或等于9 I3 ?( [; |" Y+ A$ Q
$lte:小于或等于. F" D6 D* m3 e' m5 z/ F7 K/ C

* N7 @) x& Y  d3 o6 T例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value; q  y7 T8 J( J3 s) v# D
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    2 ^" D+ \! o# w* x, F' z2 g
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value* s7 K; W: ?; V
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

* o6 Z, L7 c4 l9 n' }& e( M
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});0 b) Y' y5 q* n' w2 @
  2. db.things.find({j : {$gte: 4}});
复制代码
) ~6 s/ i: a/ E
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
* H) D$ i7 ~6 r$ }% K

6 ?5 ?6 N; |6 N$ t  a( o! O; c% f
8 p8 z) A4 [) U% i' q6 h$ {
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

/ u* V; Z/ A( a+ r+ s/ `: N" f
3) in 和 not in ($in $nin)
$ N9 E+ y7 u( j! v# L7 a, q1 d; v& G4 x& T$ N: E9 u6 `( u
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

5 }1 v+ z$ i0 o% y
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    4 A/ b* I3 }1 d2 I' ]  |
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

+ k: F9 a6 E$ u2 e- ]: D, J
$ L2 i, x9 H: B* R0 D3 S. V
4) 取模运算$mod
6 F' L: n$ C9 X( S9 P, d' c
$ ?6 w3 L+ P" d* U: N0 K如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
' f# V% k8 p  j  G! P; {; ]) q  h
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

2 P, A8 G- a9 ?# k2 \$ x

' I$ O$ q" b4 [/ J4 S' C# [5)  $all7 L  p% M( M0 R. x
+ J* n6 ?0 ]7 r- ^& d7 V
$all和$in类似,但是他需要匹配条件内所有的值:+ f# ~% x5 I+ Z5 Q, W5 |1 a( _+ i
5 j. V! K' v8 ]! [: I9 n
如有一个对象:
3 a7 S/ i# H7 l& V8 j# c
  1. { a: [ 1, 2, 3 ] }
复制代码
0 R8 J( A, X8 @% p" w7 Q
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

  O! N! O& h8 T; v% L. B
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

+ a( ~5 l" z) ~9 P
. c+ O& ~, f1 ~6 P
6)  $size( |! h! x0 v6 {# u/ o: r

1 x9 M+ H- ?( ~5 @/ t: H$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
7 l4 @$ l. q5 Y5 ~3 L
/ B0 S0 [) S9 _* L8 x5 E2 e, m" G5 W下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

( \7 t7 @) L. V4 P
官网上说不能用来匹配一个范围内的元素,如果想找$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.
2 ?- W* }: p- w, M0 [) q3 P
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    6 Q0 I% V9 g6 v, K1 C* ^& c* U
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
% Q0 C' z1 j- u1 L: E7 C. E6 H, R
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string  C$ K! c6 j) I; v! k4 M
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

$ w! F3 I( y3 r) N3 C5 {
9)正则表达式# i/ k4 p1 S$ q9 T2 G; I' X; L+ |; y
7 N1 x* I8 i, }& v  C3 T* p
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

: b/ h  N& l+ e+ q9 W
10)  查询数据内的值
. Q7 [3 C# S5 a- E& N
' a! V+ W( h+ L8 L0 H+ o3 x下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
; x4 y# I$ V8 a4 B1 [
11) $elemMatch$ D/ J- E: X# X! W

4 B7 j% I' P) z  q' N0 z如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    5 v: e8 m" ]( @4 w
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    ; z9 X1 h* Y3 t
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    1 H- E: D$ o5 K! s8 ?" W
  4. }
复制代码

' n. [) ^# W9 _6 _1 v- P* _$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )+ X, D! E; y  \! B& p! @
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
9 z! x/ s* H) n/ u- L7 N' `. t! V9 s9 \
3 P* \$ t3 J2 _, E3 A12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

& e- s/ ~1 f# ~. L! A8 k" ?: X2 t8 M
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

+ I- m$ l9 t2 @9 D9 {! W7 x
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

6 x) H9 F4 T+ h. F' }6 N
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

- }" W: g3 o0 `8 T* u0 V: Z
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
9 D  N: q  C; ]
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

* Z' y% A- T% `, R0 _
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
      o6 r7 F! Z; D1 {' f
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
3 N7 x# {/ t2 ?! Z
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
4 Y5 S! G7 T$ E: I! D8 g: l3 b- C9 x) v) y  _/ g( H0 N( _
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
7 @! H. o1 L2 A% A# o) o! L6 l, W% r3 y, Q7 w
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions8 V: C) `9 A) b) n4 m6 K. ]1 }

( F0 ?, i( ]' w: D6 L版本二:
( [2 V! U6 I; Y( z: L" `) x3 j& j
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
) d+ p# d( r! j
  1. use admin
复制代码

% Q7 G# O$ T9 v. b2 I  p
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

' ]5 I# n6 p6 h  [
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
0 [; m' F/ @% Q, R/ A, k6 k
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

: x( ?+ h8 o9 d- z0 @* v0 T
         5. #删除用户
  1.           db.removeUser('name')
复制代码

# u0 W8 ^( G, R- c# x* P
         6. #查看所有用户
  1.           show users
复制代码
' Y, X5 I2 z3 a4 h& |9 O! z
         7. #查看所有数据库
  1.           show dbs
复制代码

5 ]6 C6 L2 z9 Z
         8. #查看所有的collection
  1.           show collections
复制代码
0 w3 q; d1 u$ ?1 ^5 Q! M
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

0 ^  P8 c. d# I
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
. T& c! O! i# ^( ]0 _$ r8 [9 e
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
% P  p$ o) h/ Q9 W7 N' H6 d& X
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
4 ^$ U2 l3 A% h9 v" `7 f
        13. #查看profiling
  1.           show profile
复制代码

: F* |8 M4 J+ a4 ?/ v9 i1 K: D
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
% J& j+ K0 s; `" m3 L6 q1 d7 a4 @
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
& d2 |$ |8 n1 l8 f9 o
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
- ~* B, o3 U1 r+ \
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

# r9 I1 ~, v, b8 d
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
; \0 K+ O, }- q7 i! ?
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
( {: c3 C5 t2 r4 k
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

; [7 c: n1 m* k& T& c
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
% s; H- h2 h, X8 K% c3 k
   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()

% E. Q' y: e) k) }( K7 Q
6.  高级查询
条件操作符
$ q, J7 R7 Y# E- n9 r9 q0 O" f
  1. $gt : >
    9 c- w$ Q* S% s8 k
  2. $lt : < ' m( @1 H1 _( I( C( u/ K; K
  3. $gte: >= + u: J7 o& d& I( M% n
  4. $lte: <= ) i; d; ?0 z' k, c) J# ?
  5. $ne : !=、<> , N3 I8 Y- s3 f
  6. $in : in
    ; W  |9 w% N: t6 q$ f0 I8 W3 C
  7. $nin: not in
    8 E6 k; R) ^8 z& A8 t. _1 N7 K
  8. $all: all ; O: w0 \1 j& ^! v5 Z7 F3 [
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
' X! j& n, I# O: }

0 s. ^" x- }/ q2 c查询 name <> "bruce" and age >= 18 的数据
$ k: \+ P, s) }
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

( h9 Y5 x) p# N% k2 ^% \4 x, R4 g" }( ?# R3 B  f. H4 x
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
6 D! \; `& \) I) ~; r
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
1 x- ?3 v9 A9 v( H3 ?3 T

' E' n1 P5 ~9 B  g  u查询 age in (20,22,24,26) 的数据 7 T! C7 H& z9 Y9 `- D1 {) A
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
6 k7 H' c/ G7 z9 j. T
5 e/ Y4 e, `5 |
查询 age取模10等于0 的数据
% f* D5 u, Z( O  u0 {: W
  1. db.users.find('this.age % 10 == 0');
复制代码
( V' R# s5 g# _9 q
或者
' Z  p8 r6 B; X3 b
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

$ a2 z* R3 Z! `: Q" V) O5 U  R6 b6 N6 \! B, p" k8 D
匹配所有 % T* w* m( o2 ?4 u( N" G) p
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
1 G8 g, V* G- l9 l, J
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } 1 g* t+ ]: c: K+ R2 E0 j+ v" B
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
: \$ A( j& q4 X( H0 [8 O& c
- P5 A! k$ o3 k0 N+ v+ }3 n查询不匹配name=B*带头的记录 : x) F# [9 \8 e1 k/ O! P$ c
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

/ X7 D# Y2 q3 B4 z- s, @' a- C4 W查询 age取模10不等于0 的数据 6 G7 W8 T# R" s- r- O' _( j1 p
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

( {4 @. r5 ^, I8 p$ ?2 Y% m5 e, F- I, C
#返回部分字段 + z# i% @9 T; Q1 l! _; w
选择返回age和_id字段(_id字段总是会被返回)
+ Q0 b! G) p' l3 y% A+ I
  1. db.users.find({}, {age:1}); ( b/ ^% Y, |- R( \- q
  2. db.users.find({}, {age:3});   b* E$ ?* o. X
  3. db.users.find({}, {age:true});
    3 x- @0 n6 @& U( ^
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

. V% L/ [# P, c! u0 T8 [3 w0为false, 非0为true ; N4 I) T% l2 s5 y' H

* \. ]1 B' z4 |  u+ W$ t, e- p选择返回age、address和_id字段 2 M( `# J/ z6 n- W
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
, P/ ?: D5 I9 Q' ^7 ]: ~5 b" }
) U, G, o- N; G( E, v0 J6 ]
排除返回age、address和_id字段
: B$ y* v% r$ y* z' `3 M
  1. db.users.find({}, {age:0, address:false});
    1 @  d; f! Z4 A% _. D2 N" p2 R
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
# Y  d7 \* [1 Z1 @. [

# ~' w6 `; H- d6 S8 a2 U6 T数组元素个数判断
  c7 \7 `! o( L5 ^2 n* C, _" d4 V+ B对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 $ A; ]- A0 f+ B7 J; q
匹配db.users.find({favorite_number: {$size: 3}});
& V9 d# O, E( h. ]6 e  x不匹配db.users.find({favorite_number: {$size: 2}});
4 ]/ N& b! Z% m: K" Z
# R! X; V. k# B+ `" X+ |$exists判断字段是否存在
  f$ o) c5 r( M4 t查询所有存在name字段的记录
# D) \5 i% k1 F2 y7 I$ f
  1. db.users.find({name: {$exists: true}});
复制代码

+ p. e* v- o! W. @! A* g- N- E3 I查询所有不存在phone字段的记录
3 {" {7 G: b4 _, ^4 k& Q) b
  1. db.users.find({phone: {$exists: false}});
复制代码
2 i5 G6 v0 T: T) R

2 E, w/ e$ ?' }$ D! |9 N6 r$type判断字段类型
3 w" v. q. c0 h/ R查询所有name字段是字符类型的 * o) \1 d$ K7 h( e' X) F- \
  1. db.users.find({name: {$type: 2}});
    4 |7 z3 Q0 E! ?2 D
复制代码
  t. J' y, Z' Y
查询所有age字段是整型的 1 D" m# N( e7 ~, y) u3 A
  1. db.users.find({age: {$type: 16}});
    , T6 `  m0 T( F
复制代码

6 L+ i' m: E7 b1 |: w: i对于字符字段,可以使用正则表达式 . [# j, W' W" b8 x6 Z( i
查询以字母b或者B带头的所有记录 2 [& l! K  ^" N# E9 b2 ?% ?
  1. db.users.find({name: /^b.*/i});
    ; H2 u: x% o; E) z4 f: e- @
复制代码
8 i* n7 D& |# ^9 E. R  M
$elemMatch(1.3.1及以上版本)
. W& \1 t" c4 B; c/ `% o) J为数组的字段中匹配其中某个元素 8 I1 b0 U/ C7 ~9 g8 H2 h

0 |4 d, u9 ^9 H1 k/ n. |* vJavascript查询和$where查询 + ^6 M2 W- N% ^1 |
查询 age > 18 的记录,以下查询都一样
; f& V5 ^, o3 c- [# K/ }
  1. db.users.find({age: {$gt: 18}}); ; R- ?3 y- _. `( v
  2. db.users.find({$where: "this.age > 18"});
    & g6 {! k' P+ y) T
  3. db.users.find("this.age > 18");
    / @* X" e: Y" S6 n0 c
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
. T8 H, B5 d- r$ V0 s; k- Z+ M

, f% p6 e9 H; ]- J, }排序sort() ) i1 B1 i9 `. O6 y) f: [$ H$ Z
以年龄升序asc ( l4 {7 q4 l# U" g; l4 [0 u* w* Z
  1. db.users.find().sort({age: 1});
    ' w: M' e0 n: l! ]' F6 w0 }$ T, A
复制代码
# m5 i, [* X. d1 W& A
以年龄降序desc
& H' \+ o5 `: g$ d# J: p
  1. db.users.find().sort({age: -1});
    3 p3 k8 s  E9 j& t% @. G/ D
复制代码

* y$ u, ^# z' D" Z/ O2 \7 I限制返回记录数量limit() ; y; N+ N+ t) [' F
返回5条记录 0 A" T+ v, o! s, t" s: k$ y. L. G
  1. db.users.find().limit(5); , k3 y* k9 q' |7 b7 `$ V, d3 t: C
复制代码
3 d: p' d# U% l  b$ t
返回3条记录并打印信息
2 w% `& z* H3 a  M
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    ( c$ Z. |# w# N2 {) e) d
复制代码

2 p) |7 o8 x) Q1 v( o/ m: P结果 - J2 \' [& ?" ?0 [/ Z/ T0 N
  1. my age is 18
    / r7 K$ r  _+ {, m& }" V, U5 O
  2. my age is 19 " r* p5 u; c8 J, [9 f- S4 X. _5 f
  3. my age is 20
复制代码
3 G5 h. w- C! v2 ]4 n! T/ s
3 I) o- ^# ]0 s- w9 W: m
限制返回记录的开始点skip() & ]! s$ ~1 Y5 |3 D5 h
从第3条记录开始,返回5条记录(limit 3, 5)
9 z* k, r4 T. R+ S
  1. db.users.find().skip(3).limit(5);
    2 \  j6 N1 r; j- f
复制代码

' S$ R5 U1 C& ^+ e, s0 B查询记录条数count() 1 M6 B& C1 e1 w' b
db.users.find().count(); 8 m7 |+ Y4 Z# n& j9 ]
db.users.find({age:18}).count();
, j5 }% u! _3 y: m* j以下返回的不是5,而是user表中所有的记录数量 1 i8 r4 a4 Z! @( l7 Q4 M" |8 F
db.users.find().skip(10).limit(5).count(); 9 y+ l' E& o% t4 @
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
3 E* n- ]! o0 ~1 V7 t: L' I
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
. o: p8 b& t* _8 V1 J6 l. b' ]/ Q4 ^
% B& [( }' c+ g$ T* _" b
分组group() 0 y  G4 l: V* \& i! K3 `
假设test表只有以下一条数据
; H4 g8 w# H: s4 ^4 U
  1. { domain: "www.mongodb.org" * c8 J( Q7 Y0 V0 a: ~
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    . |$ h% B. J& I
  3. , response_time: 0.05
    / M+ ^: J4 Y! d
  4. , http_action: "GET /display/DOCS/Aggregation"
    - O- H5 ?6 ^6 _9 T! ?, X5 \1 X
  5. }
复制代码
* ?% {# k( A! R
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 6 i1 r4 s- s6 l2 a0 y/ O
  1. db.test.group( % Q# a# v# }. u& [3 Q9 L) j4 \
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} . i; z( f+ d  a' r, Z5 b' _
  3. , key: {http_action: true}
    ( _* o! G+ p2 B7 _( d
  4. , initial: {count: 0, total_time:0} * ]9 H: X, B, \1 m
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } 2 ]/ K$ M2 A. G8 V2 B+ n. I3 K# P
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } ' o8 s* P4 D! ^" w( n
  7. } );
    $ U2 c1 r( |/ M! |2 t1 w
  8. % z# K2 K, J4 }
  9. [ + \* _, ]4 A. Y( N7 g7 _4 }7 J
  10. {
    " z0 }; Z( w# o1 d1 I  b
  11. "http_action" : "GET /display/DOCS/Aggregation",
    & _* o7 o. a2 C8 s# Q
  12. "count" : 1,
    % {# @9 o* M1 p; d0 |
  13. "total_time" : 0.05,
    9 X0 L. c0 Y# E
  14. "avg_time" : 0.05
    " v( s% d$ M0 q( n6 \/ p% N; k, ?0 |
  15. }
    ( u( t* L6 W8 ~1 p3 I8 P4 i% k
  16. ]
复制代码

# M% X- h9 e0 e$ s, K7 E1 p( f
" F: X* {8 ^4 \, h
% m+ V7 x- b. B; N, e2 c9 S) xMongoDB 高级聚合查询
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
    , v7 z" f9 ]7 v* q  ]
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

! y4 a" C& a7 b; u  C& {- G
& Y6 c8 q% ^2 W# D$ P, i
3 R- Z- a1 y5 Q$ |  @+ e# E
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    9 G, M; G& i$ Q2 w# h
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

2 f- z" I1 f4 _9 C$ [% f
9 _7 Q7 \6 \. x# B% u
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
6 Y: e4 f6 K8 L5 D) t; k+ B4 o

: Y* U6 F5 x: [8 y! }5 j4 m+ [- |$ N
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
3 n& ^2 N4 j2 V0 @) U9 i

# ?7 L7 u8 P- b) I7 I
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
; I5 W) y! F6 y

; d% S' A8 p- U; O9 d9 l
输出如:
  1.         ' c* ]$ _: N( W
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

* ^0 P, y# G. z) w* x8 E1 T
! O5 ]  Q7 U4 `( W! I  W8 O% o! m
2 s# S8 I& H+ H3 }+ \4 Z( q
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"2 p3 b1 ]" {. S7 a% `$ b
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    8 g$ t+ C  }: O7 V& h
  3.        xmlns:context="http://www.springframework.org/schema/context"
    , h5 c  Z8 a3 M0 d
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    . m0 Q( Z7 m! l, h  ?/ r
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans1 y* F# x2 E9 x4 U" I1 Y
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    ! M! p, |! ~2 [* `. D; r
  7.           http://www.springframework.org/schema/context9 S3 R$ e# O! P
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    4 m3 e! T. Q, a; V
  9.           http://www.springframework.org/schema/data/mongo
    ! b2 n: |3 Q4 e  h4 L
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"># c# m) ?8 S: b' o( A9 f6 S2 ]* r$ L

  11. + ^" I5 i& t. c  P# m
  12.     <context:property-placeholder location="classpath:mongo.properties" />! E5 T$ x9 ~) B
  13. * |' r% V/ U  x. Y
  14.     <!-- Default bean name is 'mongo' -->. e/ r% |, d- `
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    4 ~- n, l# U( D, Z, l) b
  16.   q6 q9 ^! b- \7 l- y' s6 y
  17.     <mongo:db-factory id="mongoDbFactory") F/ ^1 H+ e" q- ^" c
  18.                   mongo-ref="mongo"
    * A: `: g/ S7 ^
  19.                   dbname="mongotest" />
    - L$ b$ q/ k4 a& O0 u: m

  20. # `  X7 H* k+ G7 U' r3 [$ J
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    - p* ]' q( n& ?9 m7 k1 d
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>; H) h$ {* u- B! v
  23.     </bean>
    ' n0 w  }' N, s
  24. </beans>
复制代码
5 E4 A+ t9 L, n% S, ~

- Y  b1 b: A& ^3 |, k; f' a
maxmin的测试
  1. @Test; c/ d$ O7 W3 D5 s5 c; e- n6 G
  2.     public void testMaxAndMinAge() throws Exception {
    / a# I/ q( D  g) c2 t9 |
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);2 g  V$ \: t0 ^
  4.         Person result = mongoTemplate.findOne(q, Person.class);, {  J2 s$ u9 }
  5.         log.info(result);
    : ?% L8 g6 {6 b! d" T1 Z

  6. $ |% C: O" a' K& ^
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    8 ?, i4 l+ R  y, _' S" G
  8.         result = mongoTemplate.findOne(q, Person.class);1 L! b6 f" s; z' P/ E
  9.         log.info(result);
    ' O0 x: \( G5 U2 \- n3 A) u1 A9 r
  10.     }
复制代码

  j6 r2 a- {8 |
/ O  c; y9 K% w$ S5 t$ r( x5 c1 S
distinct的测试:
  1. @Test# N* j3 I, m8 }( @. O8 ]: P" y
  2.     public void testDistinct() throws Exception {
    3 ^  x% H6 ~" L7 n; X7 m5 d
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    . g  m5 E; t; @, `, h
  4.         for (Object o : result) {3 ~! b% t6 X# y) ?# M, U! y
  5.             log.info(o);) |7 h9 S$ {9 I6 k
  6.         }! b0 l0 _% K/ I% d: ^+ z

  7. - S( n. R' u: B
  8.         log.info("==================================================================");+ A$ T& D) b8 n- P
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));1 S: ]9 h8 {' x. ^' o+ i
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());7 n! b' i; Q. E6 V
  11.         for (Object o : result) {8 T1 v+ d; @; p: |
  12.             log.info(o);
    5 @1 V, J  `8 E2 ]' k8 b2 g
  13.         }
    ' g5 R6 }0 l6 [9 Y( M
  14. 3 {0 K/ @/ Y: s! g- x  Z
  15.         log.info("==================================================================");
    & E0 ~- F* Z) a: j, `
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");0 J: K2 z: k* L+ ~, W$ P/ O2 b- e
  17.         for (Object o : result) {. ]/ x, z: z! _9 H9 `5 r4 N. o
  18.             log.info(o);
    % I# b& {% I; J
  19.         }
    ' C$ ~/ N  v$ r7 s
  20.     }
复制代码

& J$ t( E6 @5 x" O
& ~7 w: k7 D6 [* t) L3 z) z* Z7 i
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567, F: v1 U1 C9 H6 a% R# U
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    9 t0 n% H, v- }+ @0 k
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    " {$ a8 n9 T2 q5 K3 _3 |
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    . C8 j, V0 @' |. J8 x& l+ t
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    ; s( l3 r# v# v9 y+ {+ j7 l
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo& t% [8 z9 ~( q2 S5 f2 k* t9 k
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    9 x. B" _0 M! P2 M
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    2 c) N$ b2 h5 M& }5 s! d( R  t: R
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    % ]& Q& N' ]" s/ {
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    6 ]2 }* ]* O+ x" J* t  d1 [% L
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    - A) z0 v) A$ U8 Z+ F; A
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654/ A7 l" o3 d! H/ U" @- E$ s. y: s6 @
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    $ U* I- F7 W" ~1 R9 E2 @
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    9 I: k- i  s2 H: A, n
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb% V0 v# K5 i; Y: O& A
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    4 t( O7 C5 I( E! M
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    " `" I* ~0 i- K
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx. b2 u, |* t$ E  f7 n
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy* p9 ?# @# _( f& s+ Z, t
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz( @7 U+ M! M2 p0 `4 v9 i
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    + R1 x% _4 z, d4 k! @& b1 ]
  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
复制代码
( I: @8 p% x. S5 \
# \1 o! Y8 a1 Y
这里我要特别说明一下, 当使用了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等信息。

: K5 [* f: C6 H; X/ t* I6 d( N  y- i4 K% C5 H& i5 Z  `

$ y+ ?1 ^3 k5 X# r3 w
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 00:00 , Processed in 0.080998 second(s), 22 queries .

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