cncml手绘网

标题: MongoDB高级查询用法大全 [打印本页]

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:7 E$ r$ W- v- S$ q

( U- \5 }/ O. P' I. a8 E1 ) . 大于,小于,大于或等于,小于或等于
  A9 w2 c) }0 v7 n' N# {' W5 J5 T
$gt:大于, C6 B: Q8 E" x4 n! l3 D! ~$ E
$lt:小于
& }$ t- H4 x1 e8 s& S% W/ r, z$gte:大于或等于
4 S6 l1 L7 b/ ?3 h$lte:小于或等于
, i8 ?; z6 {9 G- E: g5 I: ]% u& S$ C" D3 O" M6 f1 K8 Y8 z2 ~
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value( v" `0 N4 u% R3 w
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value2 M8 ]: |' m, w$ U3 w$ {
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    8 Z( k6 h& \3 h. V  Y
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

' V! S: p7 m0 o) B4 R, S" q" e
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});) |7 w0 g# c5 n( L: S
  2. db.things.find({j : {$gte: 4}});
复制代码
+ f2 o" J% R' L& q; Q4 c! F, }9 Q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
* [$ T" }, b: _0 j% v) p+ J" D

) h* m9 f/ U$ |6 G- x9 }9 k
% [  s0 }" L$ _0 n2 j; ]
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
( P6 z! S7 z4 u, D5 }2 q: e
3) in 和 not in ($in $nin)& G: ]6 W! X: L2 L' \

/ [* ^9 Z5 Y" z1 [- p语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

; C, `* w9 d4 p( B& r
例子:
  1. db.things.find({j:{$in: [2,4,6]}});* s, S1 \, ]: Z# @
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

  T; i4 p# Y- w  q
) `/ [6 ]; `" U8 z7 u
4) 取模运算$mod
* G0 |. `: L2 h9 U3 f
1 I% ~+ K' D4 @- D如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

" \& x+ M  c* O( H: O/ Q0 X
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

6 B) `3 k" p* F/ m

5 l( U; J; W# y( v5)  $all
% H5 p% J, U6 ]1 Z7 S5 q0 A& K" N+ P, y1 f
$all和$in类似,但是他需要匹配条件内所有的值:7 N# X: l/ m, o% B+ S* p

$ @% v( q: @6 i- h, r% R0 N7 t如有一个对象:
$ L" I- X0 e% p# ?4 Z# R
  1. { a: [ 1, 2, 3 ] }
复制代码

# _! k& m8 ~( h: P
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
0 V6 ]  ^& ?. U. j
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

. r# Z& s0 Y4 K

: B  L7 M' v. j  W  ?- [9 G6 A8 \6)  $size4 w+ u# a2 q0 v" c8 A2 N+ X# N& D) R
* [7 ^0 u4 Y4 N; F% Y- J  @9 z
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:& a) m+ E) o8 {! d. }

+ [) G8 O$ m+ _' n. E下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

3 t; c2 n5 N% w/ 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.
0 L  P: k3 f- S7 p5 S! E6 d0 f# o1 g
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回" l' W, }1 [% N9 M
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
5 ~4 X  I; E- S5 @" M& R% N
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    2 Z7 v9 I  V. Z
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

# r$ i& ^% M+ B- h8 [1 }4 s
9)正则表达式
$ i: O# J8 N8 M* f
; z# v6 |  D+ V0 nmongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
) r% m; S( `4 j% R: ]
10)  查询数据内的值
/ w/ F* C/ q) u2 i- j, V8 D+ j* j; M* o2 p# H7 P! X$ M# A
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

- q- F" p) ^6 [2 ]9 ^% h
11) $elemMatch  C1 d6 ~, h- Y" a6 i4 t1 m% C
7 G. t# s- `" v7 B2 ]7 }) [* m+ k! S
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 5 o' Z! V' w$ |" t9 ?& _
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    , |" `; q- g# C
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    ' \! Y7 c+ H! C/ F* H
  4. }
复制代码

5 c4 i0 l# Y& p, b: g$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )6 D5 V% s0 }" Q
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 2 J8 B3 t: {, b6 G

% M5 {% X. W- }, Q1 n* ]- y6 V( D9 ]12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
& R; e! S% x( K( ]- Z- i
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
, n/ M0 [( C! n
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

  |- ~& H# m' @6 C. ?6 L
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

. E/ P& \) W# o9 g2 d4 d1 s. g
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
* Y: I( p, m! X2 M# D/ f+ A/ H+ d* P
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

" k! N- c/ n, g& z
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    , I  o! j+ j: y) M: F
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

% k5 v' @( l$ i. O. y$ x. A$ S
mongodb还有很多函数可以用,如排序,统计等,请参考原文。; ]$ S( p9 N% Q" B9 [6 R

' Q' O2 _6 `* a1 zmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:: v: E4 M! r& {! S3 d& ~: x

0 t  s0 p) h& shttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
. I0 U# I6 s- V6 q) l
, ^  {+ T+ X- i, Q. ~% L版本二:
- w  I5 O) @& S) ]
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

! V% X2 E. D" v# H+ E
  1. use admin
复制代码

. Z3 t: A- v! E/ @' Y* M; h+ Z0 r6 a% ]
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

, v0 O7 v% C9 k) G/ J1 j& r: y4 y! z
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

* K, W4 H5 ?7 ~
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
+ B3 G/ {% P! V& X9 @& E
         5. #删除用户
  1.           db.removeUser('name')
复制代码
3 l% W& G2 G1 h" f5 d
         6. #查看所有用户
  1.           show users
复制代码

& S8 c1 T1 x2 L  V: b/ |
         7. #查看所有数据库
  1.           show dbs
复制代码

. G8 ]4 V! b, w$ g8 p$ Z& m/ P- s1 w4 a
         8. #查看所有的collection
  1.           show collections
复制代码
, [1 Q, [: d- l2 D) U, o
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

2 [4 d) r* y' |" o
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

, D( d8 z5 c+ r- I" M& T; v
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

. [! j5 r9 O8 x4 o- F' T5 E
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

7 n: I$ O' s" x" G$ `0 E; t9 ~
        13. #查看profiling
  1.           show profile
复制代码

) s, k% L5 x) D( N" x% B# a' l' ^" l
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
' w3 a* y  f8 x5 S
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

- v, t# T, Z5 F, l/ e  ~3 i+ H" P9 L6 M
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

$ x% D/ d% A5 c& O
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

% }0 Z/ d- u; y6 l/ j9 X
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
8 X( K! E6 P2 b1 x+ J4 }
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

  M1 p  g0 I5 H0 N3 k! ?# F$ g
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

2 y. k: l7 G; T# y
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
* I2 n* z' D% Q8 ?% f1 U, T
   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()
# X% ^6 }- p  q4 p! ^
6.  高级查询
条件操作符
+ ]- Q) `1 I# A, ?1 @4 z6 v2 f
  1. $gt : > ) Z6 H! A8 E8 R6 f
  2. $lt : <
    - ~$ ~; I, T1 o' H
  3. $gte: >= 1 z8 J0 U* Z( y! z
  4. $lte: <= 5 u7 a7 M  k  t3 |
  5. $ne : !=、<> 3 C% U5 V8 T9 k, S
  6. $in : in / X$ r! D, @+ F0 N* `% h# A
  7. $nin: not in ' X- A: u/ B; T, b
  8. $all: all 1 q  o- E: _! K
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
; s, B* X! O( V/ H
7 T3 n) j' ~# C( m5 \
查询 name <> "bruce" and age >= 18 的数据 8 V, M  r; l  ?7 v* p
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
: I1 h0 q) |7 @4 L0 F$ s0 i

1 s% n& Z5 l  {6 L1 b+ i查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
( }2 H1 O! ]8 X& V1 Y- X
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

; l0 G5 o  W+ V3 D& ~' c+ V/ C. m, s! U8 t& h+ L: T
查询 age in (20,22,24,26) 的数据 # @0 J# b  R$ n  L
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

7 Z5 ^; T2 o/ D" G/ C: p& w& A" b. L, s9 C' h5 o6 [1 z9 N
查询 age取模10等于0 的数据
3 I/ |; f6 @5 Z/ d, v
  1. db.users.find('this.age % 10 == 0');
复制代码

3 V3 {' Q; a  E5 ]或者 : g9 Z) R" d' y5 c1 q
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
# X7 V' ?( l8 Q; k* M. g8 c
4 [- [6 K# b6 J  Y1 i* ]. w
匹配所有
7 c7 \5 ?& ?- X
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

0 I& {7 Z& P" e可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
8 k( p8 A1 r# i9 d  g- n3 [. t可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } " i4 \. H; G! f9 K. \- _

! ?' z& ?! U! x查询不匹配name=B*带头的记录 5 U7 d, x1 L& l2 _
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

- M$ r: ^$ N! q3 x; r# r! N查询 age取模10不等于0 的数据
- Y; y. T8 d  {/ H1 j0 |
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

  }; k. K/ D5 F7 y0 G* D/ V% I# o7 Y4 l, o, p0 b
#返回部分字段 $ _$ N" Q& I/ ~' b( g4 O! u5 W
选择返回age和_id字段(_id字段总是会被返回) * M  \  O3 R* m) b. I
  1. db.users.find({}, {age:1}); 8 v! b- K. S0 M* s8 w* D  F& A
  2. db.users.find({}, {age:3});
    5 S! r6 x' H' W0 D* E
  3. db.users.find({}, {age:true}); 5 y3 Q( L2 l) E* d$ M2 o% O# S; W
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
) U) [# d, q* S# t" Z" J
0为false, 非0为true
# O0 v5 _8 i2 z% r5 y+ g8 s" Q( C7 H9 v# @! q- K9 H
选择返回age、address和_id字段 " {+ q' G- g& y  f9 H: I) n6 I  I
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

  q6 |! D2 E+ H% h* A' ]( t+ u
% T1 q" M) b% d5 K. ~  p排除返回age、address和_id字段
* {( K' p4 Y# r. g5 @: C$ n' q
  1. db.users.find({}, {age:0, address:false});
    & }7 G9 M; b+ f6 d* R& J3 D9 Z
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

4 l8 C; N# k& ^5 S( `: R# N5 b( U6 g$ z& ]  H& c4 W
数组元素个数判断
! m3 V0 x; t, r) X5 p: l对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 9 U5 d+ w. I. T& I& V- Z1 g. a0 ^. S
匹配db.users.find({favorite_number: {$size: 3}});
* W1 p  H0 `2 \+ D" P& V4 I不匹配db.users.find({favorite_number: {$size: 2}}); ; }# v. q# Z$ m: W7 H
  O& H+ _2 h6 l; k6 I" Z
$exists判断字段是否存在
+ ^7 {% H' K5 _' l查询所有存在name字段的记录
0 E  U* o6 P1 g6 A5 U2 M2 h
  1. db.users.find({name: {$exists: true}});
复制代码

# j6 C" S6 b7 r& ^查询所有不存在phone字段的记录
6 Q5 K1 q* Z9 c7 x  [3 U4 \
  1. db.users.find({phone: {$exists: false}});
复制代码
7 x8 j2 R9 {9 ~. y& h! Q4 s( Q
9 p( H3 ?9 g3 d3 y. h
$type判断字段类型
8 j+ y( M9 [; Q, P& X查询所有name字段是字符类型的
; ~. E1 [6 P. h
  1. db.users.find({name: {$type: 2}}); & x7 W% c# [) Z- U: A8 t: m! Y: A
复制代码
" c  c. ?8 Q) s2 s' b9 c3 m
查询所有age字段是整型的
( m! G# E$ K3 v4 b
  1. db.users.find({age: {$type: 16}}); - ?: x+ Y+ G7 E- _5 y8 _) x. ]7 J
复制代码

8 x9 ?' i" B2 b对于字符字段,可以使用正则表达式 ; G, `" `+ s5 _; q7 t
查询以字母b或者B带头的所有记录 : g' e/ e4 q; u: u
  1. db.users.find({name: /^b.*/i}); 5 l8 b! j4 L- v( W! P  }$ d9 l# a& _
复制代码

/ s. F7 M6 R  h# X6 n8 e" ^4 g$elemMatch(1.3.1及以上版本) ( T& Y$ f1 B7 J  c& W" W% e
为数组的字段中匹配其中某个元素
" d6 q1 B- i& n' I7 F4 U, Z3 b; U
2 A) T3 X# X  |* ?. `8 g0 wJavascript查询和$where查询
6 ]0 [2 X# f8 y1 ]# I查询 age > 18 的记录,以下查询都一样
. H. i9 h9 i/ G; V, i
  1. db.users.find({age: {$gt: 18}}); * ]2 ?* ~$ h& F
  2. db.users.find({$where: "this.age > 18"});
    " U; z" Q0 f8 M/ c! Z/ @
  3. db.users.find("this.age > 18"); / H( D& n2 h3 u6 O' s( I
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

4 |6 r# g. g. I/ |% q2 I
$ W- r8 j$ X) `2 y排序sort() 0 @& r, [  y+ q; B; q5 A6 E
以年龄升序asc
; ]% v# C0 }2 y* N7 p" o
  1. db.users.find().sort({age: 1}); + k  A- H0 [' T+ U0 j! G$ R
复制代码

2 e- k. R+ e& A9 i以年龄降序desc " H3 ~% U  Y0 ^5 I
  1. db.users.find().sort({age: -1}); ( y# q# m6 ~. @; b4 m: Y- E4 @5 P
复制代码
. d& h$ J6 S$ T3 X& T
限制返回记录数量limit()
; b) d8 R0 ^) U$ }( [; d1 M返回5条记录 * T8 e" E  F* D2 F
  1. db.users.find().limit(5);
    / K8 i) J$ T5 z+ q2 t2 K
复制代码
/ O0 a, \: K; t) Z
返回3条记录并打印信息 ' C! x3 i- n$ E9 p( ]+ ]
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); . C8 S& i' F6 L7 _$ t6 {
复制代码
3 C3 H) M8 l; O  s) Q  w7 ]7 q
结果 % E0 H5 R& x- F
  1. my age is 18
    & W8 b. V. y+ e3 {- h9 ?& a
  2. my age is 19
    ( J  A1 q9 D+ y: K( e
  3. my age is 20
复制代码
; j/ E) m1 R- s( k* o, c

; T" I# Q8 a* n  V, I限制返回记录的开始点skip() ' _3 n1 P* h) C9 Q2 Z
从第3条记录开始,返回5条记录(limit 3, 5) ' [! L9 {+ B$ e. B  I) s
  1. db.users.find().skip(3).limit(5); 7 i9 s* g0 X9 R# Q8 Q1 t4 G
复制代码

& l% y; b! a3 `, [' _- H查询记录条数count()
5 k7 w" X2 N( W" [" Hdb.users.find().count();
. H- H! g0 \0 z# s' l' wdb.users.find({age:18}).count(); 2 E+ w. T3 v4 n, X
以下返回的不是5,而是user表中所有的记录数量 : g- n9 p* e$ B2 i2 O" N$ v% y
db.users.find().skip(10).limit(5).count();
( Q. n- c4 a9 U如果要返回限制之后的记录数量,要使用count(true)或者count(非0) - {: J5 g3 m1 X
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

& F' K3 z, }' k
- H+ m: c2 @0 }* h2 t4 |: j8 H分组group() ( b! a- E6 H/ _5 z1 H
假设test表只有以下一条数据
6 ~* V3 k: K& h# e5 m1 C
  1. { domain: "www.mongodb.org" * l% t! s2 Z: C* F
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    1 R* o5 Y1 t( ]8 s% ^" f8 m( G, ?$ n
  3. , response_time: 0.05
    6 O( u8 n6 c; p5 _- w" h, a4 Q  D
  4. , http_action: "GET /display/DOCS/Aggregation" : Y" k$ R6 E# M2 v
  5. }
复制代码

( I# Y1 O" `: N  Z" `0 c, U使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
% r- ^, i' T# ^
  1. db.test.group(
    , q  q2 ^0 P; N. s% v) {
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} # X8 s/ }* y2 s# V3 h+ T5 ^
  3. , key: {http_action: true}
    0 D) D* \6 M6 [  A* B6 i
  4. , initial: {count: 0, total_time:0}
    8 B( ~+ B" G+ y7 I% U
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } . P1 U- X) {% H( C. t2 r, l+ l9 Q
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    $ s) E( m0 Z# c( U  w- N, v! G- q
  7. } ); ( ]  y+ l" F  F
  8. 9 [4 q' A8 a: V8 H# b; @
  9. [ * Q3 G/ _0 G4 f) n
  10. {
    + T; _- ~: s+ M8 B
  11. "http_action" : "GET /display/DOCS/Aggregation",
    * y0 Z5 p" d# m  x" R' W
  12. "count" : 1,
    - s7 X* h2 s1 X, z8 u/ t
  13. "total_time" : 0.05, . f) |& o5 b7 C3 L) [: s
  14. "avg_time" : 0.05 . i* ?% x" h& e6 v$ ]
  15. }
    ) p2 D3 i. t' D1 D
  16. ]
复制代码
7 w/ u1 X. s% W1 _8 X# `

+ N4 ^9 t9 n0 Z3 p) s" ]
* u# |, I- H2 pMongoDB 高级聚合查询
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。
见:http://static.springsource.org/spring-data/data-mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoTemplate.html
不说废话了,我们直接来MongoDB吧。
  • Max 和Min' p6 D! r' H7 ]- D$ g' u+ {
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
) T: w" @# @3 G- p* E
% x! }- U- {" n- D# ]; e* a& T
5 K( n! R. ^$ F
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

! D2 W1 _% H' y9 }! P1 r9 i
* S$ W: B- n8 W5 d
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

5 E) V- M7 O/ s* x+ ?
3 A1 V' U/ S+ F! B, l( }; X
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

5 l. i: O/ g( g6 \! B
% s( t* b2 G: [+ p( L/ U
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
* b' l, w' O0 T. O
) ~+ t4 A+ Q% y( K- u
输出如:
  1.         
    8 |! M- z# \! g! Z( H+ \( S
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
# `" U! Y4 z$ k+ G5 A$ n
3 u9 T4 w2 a  y# Z( d7 H4 m6 q! ]
7 k- d! A8 E, A2 M5 {1 m
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"% p6 G) B: \1 V9 T
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    1 ?2 L" {. c6 R8 v4 p
  3.        xmlns:context="http://www.springframework.org/schema/context"/ }, ^& f/ Q& F( Y# U
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"* N" C8 R. x7 A3 J2 r" D
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans" X2 u$ Z! }# k/ v
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd9 t, m+ N' K( o9 s* s5 x. o4 Y6 y
  7.           http://www.springframework.org/schema/context
    8 R8 A  m4 m4 `
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd1 m* j( }2 X" ^+ o; G
  9.           http://www.springframework.org/schema/data/mongo4 e( R! Z/ o' I- H
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    5 W3 i7 y, }7 I3 {7 R. J, h7 I1 B5 ^* \
  11.   M. @- X" z8 S; P# Z+ D
  12.     <context:property-placeholder location="classpath:mongo.properties" />) R3 C* d+ x+ K( l! D
  13. " e- J( `) A/ Y8 a, v& ^' D; I0 o
  14.     <!-- Default bean name is 'mongo' -->
    : k. K- M( R" l3 q
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    . T# N$ x- G9 ~# J3 M. o& f
  16. % z# h0 d  @5 |  t5 u3 n- J5 r
  17.     <mongo:db-factory id="mongoDbFactory"
    " M! }0 S* M! G6 N( x- n
  18.                   mongo-ref="mongo"
    - ]2 }8 p5 J: |' f/ e
  19.                   dbname="mongotest" />2 m0 g: U/ `/ r0 ?3 P

  20. / ]0 Y4 u$ [7 c3 p. i0 [* j- P
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">; X6 q6 |3 K6 w" X% N' `2 r
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    / d% z4 x) j0 `8 M# b& x
  23.     </bean>5 r4 ^6 m/ t$ G8 b* N7 Z7 \1 ^
  24. </beans>
复制代码
! z; F1 G+ I) U' x

9 A( n, q; y0 \$ P; ^1 N
maxmin的测试
  1. @Test" m4 x: H/ N- h' P" ?% c% t
  2.     public void testMaxAndMinAge() throws Exception {  k0 A2 \" k" a, C  K6 F
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);, ]9 `( v* \6 U$ [; p& ^
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    " E/ K# X' x/ o
  5.         log.info(result);
    ) _5 B" [. L; i: I# t# @0 f5 _( N7 o
  6. . _0 n) E4 `$ d6 j, I/ l8 L
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    & o5 j9 y* s7 E+ J1 ^, ~: V3 i
  8.         result = mongoTemplate.findOne(q, Person.class);
    - t% i5 h% S: }+ d4 K$ x+ j: B
  9.         log.info(result);
    . E4 b. J$ }' m# J" {* z  h' E
  10.     }
复制代码
! S& s- y2 m7 P
8 J5 O5 g2 R+ L+ U( p. o# ~+ m
distinct的测试:
  1. @Test2 i( I& n% v% i9 L( F: G1 q3 J
  2.     public void testDistinct() throws Exception {
    . {: `. H- s. Y% W+ I  x
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");, c" Y. S- Q" q! ~# U& p
  4.         for (Object o : result) {
    % w7 K/ U/ |) w
  5.             log.info(o);
    # L8 M% o( O0 j) v
  6.         }
    ! f4 x: G$ l7 m7 Z
  7. ! w2 e2 W& h% Q& \/ O, O
  8.         log.info("==================================================================");
    ' d7 F1 K1 I- i
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));" M1 J9 K* H' n
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    4 o, j  X( O* \5 z0 u7 l
  11.         for (Object o : result) {) Z1 M7 E- z9 H* t6 z8 `' L
  12.             log.info(o);0 n; V* i1 Y. m  {# J: [8 M
  13.         }
    0 ?+ W; e( w  M5 `3 D7 C0 L

  14. $ t  K( X- j& B/ f0 Z! I
  15.         log.info("==================================================================");+ L/ t# I+ H0 L
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    # o2 X( N6 t& [+ Y6 m
  17.         for (Object o : result) {
    ) B" c9 u* [- ]* y3 P8 G0 V
  18.             log.info(o);6 O! Q0 Y, R' s
  19.         }
    4 V1 Z/ H+ W# E/ b
  20.     }
复制代码
8 d  t: O3 C* \8 x, B2 [

: b6 r% [" H9 p6 @/ W7 o) g# u
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 2345675 o6 q+ V( h* s  c, J+ `
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    * u! B; r* ^. u* a! B- Q6 T
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789$ ~# H* W0 X1 p
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654! \/ I) O8 j) l" q9 p+ l( ^7 L
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    0 O9 {  [$ x2 J+ {, K* W
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    4 d3 S& t: h! G8 p
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    # C2 j& E, [8 _% T' C1 N
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    6 W, j* c. v& K! d
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567; ~8 Z: A: j0 r( {- Z3 L( p3 R; c
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 3456781 ~+ N2 ^# x; w' y7 w  r
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789  T" P; ?$ r7 G; G6 `% J
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654$ B/ a5 X& i. c3 k
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================1 ~7 x  _7 o* _: D  X' A( N
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    9 |6 _* k) F: G0 ]& {
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    # @/ f$ t( B' M) q' s
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc# C! T+ U( {& B& B
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    2 T8 Z8 c# Q+ X8 v
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    ' s, h, ^! @+ n. V
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    , j& @* C' s: Y. ^, U
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    0 I' m3 p6 ]% q% E; f8 Y4 c
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    / }  p: C) b" \/ z, a# T
  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
复制代码

' X8 X8 w9 d% X5 F. a- W- O
! P' D4 S* n$ f" S! X" T7 c
这里我要特别说明一下, 当使用了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等信息。
$ Y  s( m& Z3 w9 t# G4 C

: F5 }( Y) d" }4 X+ O. |% R4 |6 U3 r2 H4 ]- p) H" U8 o





欢迎光临 cncml手绘网 (http://www.cncml.com/) Powered by Discuz! X3.2