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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12489|回复: 0

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

[复制链接]
发表于 2019-7-4 17:21:36 | 显示全部楼层 |阅读模式
版本一:; G9 q* E3 y0 j: w# N+ A
' p6 K9 M* P4 y: u& u, k( p
1 ) . 大于,小于,大于或等于,小于或等于% z1 _; }% h: W; x" u" a' \/ x

! I: ]6 P, R" M4 M% `$gt:大于
4 b& g( v' w9 B4 [0 ?7 r% E* Z2 ]* t$lt:小于
) [4 u/ \9 T2 ?0 z8 p$gte:大于或等于2 n: n7 x. P" X, o1 ?3 I
$lte:小于或等于# l/ g9 B  y3 N& s6 _% t

& n- V0 x. b1 r. ]6 X9 U( ~例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    ' `0 J% \7 R7 {* ~6 j1 W# w$ Z; l6 d
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    5 \: w  t" U! s: X7 W2 u( k9 v
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    0 b- l4 V5 }$ K
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
: E! c. b* `' a8 Z4 T1 O
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});4 t0 _+ S: l( p( j
  2. db.things.find({j : {$gte: 4}});
复制代码

- l2 h  T) l! C2 }2 F) {
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

: e, m2 m& w0 h% J' ^, H
, O2 @7 C5 [3 y( ~- i) \
' K. A& N7 f& t- I
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

1 u/ T8 O4 U* t5 m4 ~
3) in 和 not in ($in $nin)
! }9 U+ u4 t3 A4 q5 i* L
% A4 y+ k2 g- J1 }8 H: a语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
. }6 L; t* Y% Z
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    " A' |$ c* A' ^  P" j$ O! Z
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

$ m1 D" t" K( H

& o1 A3 r/ x) W4 I4) 取模运算$mod
9 Y4 M% c7 R4 T7 c. G$ X1 H) E) V. Z# B; B3 e
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
2 K4 G1 k! Z& o2 q* D
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
4 Q2 }+ m% |9 V+ t
0 h# d4 `8 q% P  G6 u
5)  $all' i% e% n6 [( V

/ D; e) e2 C- b8 g( ^$all和$in类似,但是他需要匹配条件内所有的值:/ q6 k6 @- H' K, c% N
4 |: J/ t5 [$ q0 H: c1 \0 u. ~
如有一个对象:
) D- G2 F8 i5 m9 E, P( G
  1. { a: [ 1, 2, 3 ] }
复制代码

+ h- W/ Y3 w5 b% s8 U+ C
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

0 M; [8 b" v. n4 }
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

0 b$ @; H9 J& e& }4 |3 X2 V

3 g' z( l) @" {6 v6)  $size
; P# `  {, [$ K6 \! F8 @9 ~1 d1 v* p$ r
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
8 Q1 E8 f: W) q6 ^. ^
! ?/ b: O7 I2 c: k下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
4 n+ v6 `3 t7 P0 I1 z3 l& |
官网上说不能用来匹配一个范围内的元素,如果想找$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.
& d( B2 ^! j' B" y
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    5 o: ^0 M( r6 d5 E' Y% w
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

* a: R2 m- l5 O0 \; F
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string3 x: R' z7 O* D3 j& Q# _# x
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
/ w2 [. x6 ]. c+ [1 Q
9)正则表达式
* N# A* R9 g2 @+ i. Z$ q0 J" f  t1 n! q+ |% u1 |4 V- W
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

2 F) F- E& E% b6 ^1 u7 R
10)  查询数据内的值
  d1 _- V5 T1 I4 \3 A* N) s2 _
7 Z: I" T' I) R4 P; j$ B" u下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
) |# x7 v6 n. r1 y$ x2 @* q# t$ N
11) $elemMatch( k+ o3 a2 C. ~1 s0 K
% m/ w# _& z! @" `  ]5 n
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    7 @: z" k2 g. k. I5 m
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    " c8 X0 k! k  Z; U. ?
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]9 @" Y* W1 C! G+ f
  4. }
复制代码
3 @: T1 h; a' ?/ K: I+ w/ q! P
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )# h/ j" k% h& G8 g6 O. y! f$ T" ]
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 1 Y7 Y1 ]& _' q
, O& V# h( K6 L0 g0 L' B
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
: x% B  |2 L3 {! G. q- ?! I; W
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

' ], T% g6 a6 T: Z
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

+ p( j' K0 P2 O2 A; w) O
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

% J/ n" u3 i* B9 O
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
5 Q3 s+ Y( t0 b5 v
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
- X6 @( \2 ~2 M/ p6 [$ ^
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    2 m: F, C$ P( f! q3 S" g% V
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
" r( P! w- _; G( s  r8 O' r8 q* f
mongodb还有很多函数可以用,如排序,统计等,请参考原文。& D% V0 r0 L" L

% @3 [+ I$ [; c1 K' Fmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:; n$ s  p# o  o" u" e8 ?
5 B1 x) Y$ G, T8 V* v- g
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions" \4 C* X; z1 @2 S2 ]

! @  ?  ?$ W% ]2 C/ ^版本二:& f  C% \4 c# _- k
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
8 \. g( @: Y2 |* z$ R: Y* m# {- U
  1. use admin
复制代码

$ [' ~1 S2 L9 _6 O
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
+ u( `9 k* n% l  ?
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

# i/ i  B0 x  @' t5 `5 S' O" F* S
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
/ b$ m5 c5 ~" T' B/ ?$ T) w
         5. #删除用户
  1.           db.removeUser('name')
复制代码
" P* @4 e! Y4 v
         6. #查看所有用户
  1.           show users
复制代码
+ f: W$ b( t8 [* n  k- |/ C
         7. #查看所有数据库
  1.           show dbs
复制代码

7 X% A: B/ W. c  P# t6 L( A) p  r9 \
         8. #查看所有的collection
  1.           show collections
复制代码

3 [2 ?' P% V( D, o+ N* P
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

9 K, ?4 j3 j5 V. I+ E8 J* |
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
+ J% {! k& @& K& ]+ `1 R3 J
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

2 b8 y- J8 \+ t# O7 n- F4 J; E
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

4 e% V4 r& _# y$ p  ?  f
        13. #查看profiling
  1.           show profile
复制代码

' e' [% s+ v0 `5 [) P
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

7 t  s% V4 b! d& F2 a1 c1 e2 @
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

+ ?5 X! V: s- H& d' l; Y
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

5 W& V6 b" v- Y% |4 Y. x( H
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

7 ^2 a. U$ k  q4 G
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
0 r5 w4 C. r, C+ u$ o# m
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

; Y) w- c( l# a' L6 H
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
. W8 Q# h; @+ z- ?; L* U
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
0 G$ G, O0 X0 t# I, ?$ j
   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()

; G  W" b9 {6 ~- n( Q+ D: H0 v4 s
6.  高级查询
条件操作符   N5 r! X! |" {
  1. $gt : >
    4 x" }1 q' a1 V7 C
  2. $lt : <
    ' @4 n0 k) j3 N
  3. $gte: >=
    ! d' T) E# A/ P2 g
  4. $lte: <=
    ; x1 q2 V$ n/ l- |) P: W
  5. $ne : !=、<>   m* h( ]9 X% y) K
  6. $in : in
    2 s) q6 ?+ T2 J
  7. $nin: not in ( g  H! T( `% c5 n& p+ l5 {9 V
  8. $all: all 5 N6 E; u. r+ e# }" a7 ^
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
. p. [9 D# T/ U# e

# R2 `) k$ p  j/ v查询 name <> "bruce" and age >= 18 的数据 7 O5 L8 U& w6 e1 B# X! b$ ]
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
7 Q6 w6 `1 b9 z( Z8 Y

$ y2 [3 a8 d3 \5 [* m7 b$ C查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 ! `, J' o' w) }# T
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
4 t$ |1 c1 P/ ?9 H; k- M  G) p( a  \
3 W# y+ C( i1 q
查询 age in (20,22,24,26) 的数据 ) X  M" Y7 \" y
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

2 r/ }  \" P/ u
  M- G0 W' U1 l! t8 g( R查询 age取模10等于0 的数据 + S3 x0 u* d7 C- B3 ?8 w
  1. db.users.find('this.age % 10 == 0');
复制代码
3 P. p: V- P$ r8 L
或者 " M9 E6 X$ ^) |* q
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
1 e+ Z$ K! J1 ~% D9 a8 u, {
. J- T1 v: x  q$ V  Z0 p
匹配所有 . e8 Y  p1 C6 d% k9 |8 @
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

! e+ S7 s8 B" c% w/ J可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
9 E* I1 ]4 o& b可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 0 Y; }2 e: f# ~1 e

. f8 W: ~6 X" L" ^! d2 U3 @4 ]; z6 \查询不匹配name=B*带头的记录
$ C, J6 ^6 C8 E
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
: M& b% r- ]6 B9 V  T( Z
查询 age取模10不等于0 的数据
; b1 l! k7 q  G% X* L
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
# |& r4 Y, a( E: ~: {

; H- M2 U7 r  J* `/ W#返回部分字段 ! i# @# O  A8 P6 n5 e6 P
选择返回age和_id字段(_id字段总是会被返回) & f! F0 U9 O, u* V- s8 h. r/ p1 F
  1. db.users.find({}, {age:1}); * @' S9 g1 }* n# `+ @. m
  2. db.users.find({}, {age:3}); / _+ F! x6 Z& q7 R, u  T
  3. db.users.find({}, {age:true});
    : \' U& A, E, I/ Z- k# }1 e0 g
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

: x; l, `+ R1 w: q0为false, 非0为true
. `& ]1 ?) `3 _! U  v( N7 v+ t
4 w& p7 u1 `  o1 A8 p选择返回age、address和_id字段 ( E. n- j) k9 y( D
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
. E8 q5 X- j- D. B4 a, h- P) y

! O" M7 ]5 w& l2 W排除返回age、address和_id字段
2 W  n% z, Y4 J- x
  1. db.users.find({}, {age:0, address:false});
    0 p  h: |2 g: n3 r3 F
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

; \! o# h0 V6 i& {
% G. e& c) x% D( Q数组元素个数判断 8 U. C+ b) t  O
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
+ Z  U& g  }5 F+ N: K% ~匹配db.users.find({favorite_number: {$size: 3}}); ; `6 a8 O7 x' Y+ [$ C
不匹配db.users.find({favorite_number: {$size: 2}}); 5 D6 i: `; {& l" d7 q8 c& e

# b% c9 E2 z: j5 s$exists判断字段是否存在 * B: H9 E: V" `% }4 Z* I. c
查询所有存在name字段的记录 # a0 y7 V* z/ s+ B5 u
  1. db.users.find({name: {$exists: true}});
复制代码
8 P: S3 w% A; E0 N  s& c* ?2 J
查询所有不存在phone字段的记录
& T6 R( l4 |3 m) S. `( o+ k' o
  1. db.users.find({phone: {$exists: false}});
复制代码
, r" x, ~: x: D. J

: G  f5 N0 E# l0 V$type判断字段类型
9 A4 E; o, w9 Z0 h6 x% n查询所有name字段是字符类型的
/ |% t6 }) W( ~. t- \! Q
  1. db.users.find({name: {$type: 2}});
    ' |/ x6 K! S& D) `
复制代码
2 F  L/ p, V. z2 K8 P; k& u
查询所有age字段是整型的
; b' `! Z% Y# U8 k! @8 l$ ^" H3 n) {
  1. db.users.find({age: {$type: 16}});
    9 t- B: T, z9 V: G
复制代码
% L6 s; i8 p8 _9 G
对于字符字段,可以使用正则表达式
) ~  M$ B# w  _4 U* e查询以字母b或者B带头的所有记录 . i( r' n2 V1 d  k3 `  ]
  1. db.users.find({name: /^b.*/i}); ; D. r* r  ^, d
复制代码
+ Q* C$ p8 C5 ^1 l0 _
$elemMatch(1.3.1及以上版本) 7 T: ?- R) A/ v
为数组的字段中匹配其中某个元素
3 `3 d) X1 ]% x, Y" I; l
/ N, p5 O+ @& g$ h* y4 bJavascript查询和$where查询 0 b! u6 @& S: B4 S
查询 age > 18 的记录,以下查询都一样
  e. }# p3 M& a
  1. db.users.find({age: {$gt: 18}});
    4 `4 G. \; N. X- q0 y3 y
  2. db.users.find({$where: "this.age > 18"});
    4 E/ H! ]# x+ `4 `/ h: P3 b
  3. db.users.find("this.age > 18"); 6 Y) x; m2 V8 A9 t! \
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
! B5 l& i4 b: E; T/ c. f

" K, @8 J7 J( B) w8 B排序sort() + @- y. C  Q! u$ P, m2 d
以年龄升序asc 6 w  r2 Q/ i- x! B$ m, i- k5 `
  1. db.users.find().sort({age: 1}); % o1 w& p4 ?* T+ ~6 m2 m. l1 {
复制代码
9 R+ b! H4 Y( O+ t% b$ L9 M
以年龄降序desc
8 p$ L# N  S; d: s' W  ?
  1. db.users.find().sort({age: -1}); 2 @5 f- r5 R( ?: L; X
复制代码
3 u% ^9 W% d0 ?1 ?1 i* z$ A
限制返回记录数量limit()
2 k9 L  W. K' Y5 P" o/ l6 o4 `& I& ]返回5条记录   `; f6 {" c8 y- b$ Z! P; n; L
  1. db.users.find().limit(5);
    " N9 i  d% _6 u" |
复制代码

5 w$ P7 d% ^) t" [7 U返回3条记录并打印信息 - m/ a7 t! v& ]' f3 s+ t+ Z- d
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); & G  N7 [% K6 h  {2 W9 s
复制代码
* x2 v) p# d+ }- I- f; Z4 G& _
结果 . _2 T( N  R- D$ F6 |
  1. my age is 18
    4 Y6 L: k1 \5 F+ C
  2. my age is 19
    ( u8 r. t# C- g, i0 G5 L
  3. my age is 20
复制代码
1 k, a6 A0 \- M7 `0 L& g6 ~
# b: y4 P- D. z& l( [8 u. a
限制返回记录的开始点skip()
4 y' k, P6 e0 V9 b& `5 i2 m4 r5 E从第3条记录开始,返回5条记录(limit 3, 5) 4 k' x+ e" d3 W  ?* X, o" m3 n) G
  1. db.users.find().skip(3).limit(5);
    2 M+ F" o* z' z
复制代码

% @% R; |$ \% \查询记录条数count()
5 T; x( l3 a3 m! M7 J; U: O/ odb.users.find().count(); ; _0 s! B( G% R! [
db.users.find({age:18}).count(); ( s* F# z/ K' H5 K
以下返回的不是5,而是user表中所有的记录数量
4 S7 {* M% Y( b6 ]% {db.users.find().skip(10).limit(5).count();
; w, t" c7 r- o; E: D如果要返回限制之后的记录数量,要使用count(true)或者count(非0) / {( i! k9 \# M; F3 G$ V( }3 a
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

% o0 ~  F0 i7 o; L; c  x
" i. g+ h8 a  @9 H0 c分组group() 5 |% z9 Y7 `# k) T5 @" u" U
假设test表只有以下一条数据
; c& x4 z! g0 c
  1. { domain: "www.mongodb.org"
    " N9 b2 t- f5 z
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    6 e, c9 o. d2 ?- n' d& x
  3. , response_time: 0.05 5 F2 j& C/ p+ X1 S+ i6 P
  4. , http_action: "GET /display/DOCS/Aggregation" + Z2 p4 |+ y9 y  U: \3 u# ^( \, Z- {
  5. }
复制代码

  V6 e8 [: ?( P4 E# B# Z使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; ! D' `/ Q/ B) O$ q
  1. db.test.group(
    / `( a3 W* @; o; V; L+ B
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} 5 [+ d* c* Q( x8 {$ e4 S+ G1 V
  3. , key: {http_action: true}
    * [( I1 g, H2 X, C( ?. z' O: T9 \
  4. , initial: {count: 0, total_time:0} 6 s' q, B" l, f3 \* d6 I  @6 }
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    ! [! |9 j- q* [- L$ M0 l2 D
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    7 r+ S0 [2 U* y4 {% a
  7. } ); + \! _7 I6 n6 ~3 Y  w

  8. , y! z: j5 b$ r$ ~9 I, i
  9. [ 0 \. g: J2 x4 N4 B6 m" X
  10. {
    ! F% P1 f8 |" l! q9 p
  11. "http_action" : "GET /display/DOCS/Aggregation",
      W4 M2 M" a, I
  12. "count" : 1, ; }. K% @2 H8 N7 e
  13. "total_time" : 0.05, 3 v# y" o' ~4 F' B, U+ |
  14. "avg_time" : 0.05 0 ^1 U. V/ c8 D; G& }" f% O
  15. }
    # H! g! x! N& q1 v' |$ I+ r" H9 k
  16. ]
复制代码

1 K" w/ R- e3 r9 h1 l) M+ v, x% _( N- L3 p& I$ M' Y3 Y4 ?4 _

6 d& W6 j. I" t- `. e& h' WMongoDB 高级聚合查询
MongoDB版本为:2.0.8
系统为:64位Ubuntu 12.04
先给他家看一下我的表结构[Oh sorry, Mongo叫集合]
20121225152152_182.png
如你所见,我尽量的模拟现实生活中的场景。这是一个人的实体,他有基本的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. w- R* O  @, i/ q, I+ a* a. d
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
3 `8 I+ j, }! F  h; g) u% \* _
- t- s: h' o& E! X1 A" z
5 `& O" o6 q6 t5 s# d# S+ k
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct/ B8 J( K2 [( U3 F! V: a# J
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

; j) t2 e: G) ^1 _+ x+ m, L9 ]% o% H
: P2 F- I5 D7 v/ I& S
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
- z! ~6 m9 D" ?3 G! B5 `
" M7 ?1 O* s3 f9 n
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
% l* B; M4 V% Z# i7 e3 P3 B

, c# h6 d2 A6 z8 b4 M- V& [* U" M1 S
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
: @( K- m" T; n( C/ Q

) `4 Q2 o3 H- F0 `+ V0 y
输出如:
  1.         1 G6 k- h( R, Z/ _5 g; t
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
2 r& g- H" f- D9 u% a0 f
0 }; [9 \7 P& O8 B. _/ i; V2 B4 A

6 L! V# [# R: \8 O5 Z; g4 d& V
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    2 h1 Q: T. Z  x/ W; F
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    ! g' B7 ]1 H( n+ y# ]! k( E8 M$ c
  3.        xmlns:context="http://www.springframework.org/schema/context"
    , S. D  y1 M$ m# |9 Z
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"% B$ B" }, @# X+ H6 v) W; m
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans: D) [' h" B, k- J8 W
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd- |5 c8 m  I) B7 E/ q
  7.           http://www.springframework.org/schema/context
    ; K9 [) Y2 n3 ]5 C9 A
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    # b$ P2 o8 e5 R4 T7 |: H- Q
  9.           http://www.springframework.org/schema/data/mongo4 @+ v; e8 E) T5 X+ T, i  j: m
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">2 M: H+ {6 d8 K; q) ]6 n

  11. 8 n- t1 @3 e9 c: p* |* W
  12.     <context:property-placeholder location="classpath:mongo.properties" />7 O$ r% y; i+ Z7 k* z( u
  13. ! y' F1 v1 n: W
  14.     <!-- Default bean name is 'mongo' -->
    9 O# Y* ^$ k2 h0 @
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />4 `3 [  T; i* y( L

  16. $ t7 U/ P4 r+ ~7 j5 ]* H  f
  17.     <mongo:db-factory id="mongoDbFactory"' u/ Z4 {/ J1 }  q; l% X
  18.                   mongo-ref="mongo"- g# q. {. x* L0 z& |8 ~0 C
  19.                   dbname="mongotest" /># b" o% J, P+ t$ H6 t3 A$ V
  20. $ c6 s( x/ W1 O( x
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    , J7 k3 ], G& N; Z4 F
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    5 r0 W: l1 u$ E, d/ m
  23.     </bean>( r1 c6 f) F/ M
  24. </beans>
复制代码
7 z' L+ n) L: r$ D4 h, T0 L$ d

9 s+ p  w3 K1 d' x7 v
maxmin的测试
  1. @Test0 `# h4 m7 m/ h; a% O# K
  2.     public void testMaxAndMinAge() throws Exception {9 [4 q5 x4 G+ d' b2 X: O
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    " I* v4 A1 Y9 L/ L% w$ @
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    " e6 o  k6 s5 U! U: n4 p7 r
  5.         log.info(result);
    2 C* [; I$ ?  R4 G, D
  6. " w' z  I$ S. Y7 t: M5 e5 N9 f
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);0 S. \' R5 L% U7 Y, z' Y
  8.         result = mongoTemplate.findOne(q, Person.class);
    7 R! g' u5 f2 M& c, t; ]
  9.         log.info(result);6 j0 i# l' T. H; D4 Z- x( S! r
  10.     }
复制代码

9 p3 R- i0 U& _  S  ~) @' c4 M. J$ E% }3 C
distinct的测试:
  1. @Test1 Y" m( k* b3 I- i
  2.     public void testDistinct() throws Exception {
    # \" @( p, r  @1 N4 Z" T2 A" F
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ; l. J  n, K1 H, Q/ `. e" G
  4.         for (Object o : result) {( N3 a' N2 L/ T( Y, a
  5.             log.info(o);  ]! F# A0 F% P. V3 m, S1 S) L7 K
  6.         }/ S: B0 N$ t& i* T6 O& Y
  7. ' W0 {# H* y$ ^
  8.         log.info("==================================================================");
    ( \, E9 r+ g7 t+ g6 p
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    - t. a3 Q& t0 |
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());+ a. a0 E0 K5 ?
  11.         for (Object o : result) {: I+ l+ C+ N/ i/ F3 {/ F
  12.             log.info(o);
    ; o5 v+ Z% Z/ m
  13.         }
    6 n$ H* \/ Q7 p% Q% e% z. x+ O
  14. " d. O: w: f+ f$ e* `' g
  15.         log.info("==================================================================");' [- L! r- d2 n3 M
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    & b3 `7 I/ v9 j; `+ Z' Q+ B! Y
  17.         for (Object o : result) {
    $ u" @9 n* K6 V5 N, b
  18.             log.info(o);( b7 {% c6 B* ]  b- k% n  C# ~
  19.         }
    0 ?" M5 x9 G& c( i- f2 d
  20.     }
复制代码

, @! U# X. Y* j2 u( @# W% w% {$ W" t# @0 x, _7 N9 ^
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567! c! s) X& y# J* S9 y/ [& a
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678( j# c  X" R( K  v9 J/ P9 t
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    9 [% X/ M( o9 z  h# m' ?
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876547 L+ X  W# G1 i9 ?
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    ; u1 f  x# _& b+ D, |) l/ c
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    / }) r2 B8 K; u# p3 P5 K
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456) D1 C& F5 J* Q
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    - j/ D' O. K  x8 N; P! R* d
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
      v+ A  h' J( g- e. _  U
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678; g1 P4 p; _! a8 D5 B8 _! ~
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    * M: \) E  [5 W; B8 j8 D2 m. [3 G
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654+ g: i" L) e4 k  }* l
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================  O( R  D! _5 @0 {2 @) y
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    2 o! f- W6 _; r2 {9 L% m! b
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    , T& ?4 |  K2 ?9 \9 d2 f
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    7 {1 g) Z! I# C' t+ ^
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    ' P- ~( J5 z4 D) O
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    2 J' ~* }! A) U
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    % W4 l/ ]8 s2 G: A  B
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz( x* d3 b& e0 s4 _* E- x
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr% |7 Q* k- W) F6 C# B
  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
复制代码
: \; W; B! z/ B3 {- Y# \$ Z6 ?
3 e, Q2 d* f( d1 f0 {3 @
这里我要特别说明一下, 当使用了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等信息。
- D. `2 x6 S. |+ u! l) u
" Z9 L* ?. b$ x4 s7 I, N. D+ }" a4 x
3 c) U2 A; |" h8 I
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2025-1-13 06:01 , Processed in 0.133957 second(s), 23 queries .

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