|
版本一:
! \% X) y% P, N' h4 W( G5 y) ^ k, \; X* k b
1 ) . 大于,小于,大于或等于,小于或等于
$ n. F% Z" @" l6 D. r0 v9 ~/ p# c+ Q1 ^0 V5 v' Z. k7 Y; w2 `. a
$gt:大于
* W; F. z$ N2 z i- n3 Z5 `- ^8 s$lt:小于, S6 h8 M' l8 `+ t9 N
$gte:大于或等于
9 w7 x6 Q" z# N' s# w s" z$lte:小于或等于# p% O$ h* D2 |+ ~- W
) o0 P7 s2 d- n& A- g5 T8 E9 u
例子: - db.collection.find({ "field" : { $gt: value } } ); // greater than : field > value) ^$ d ]: H: L9 o
- db.collection.find({ "field" : { $lt: value } } ); // less than : field < value
[6 K' X# \! \3 S* A( i - db.collection.find({ "field" : { $gte: value } } ); // greater than or equal to : field >= value+ x- N$ b4 Q2 Q
- db.collection.find({ "field" : { $lte: value } } ); // less than or equal to : field <= value
复制代码
+ \5 @" z' ~1 i. ?# C" w3 g& x如查询j大于3,小于4: - db.things.find({j : {$lt: 3}});
, M) q" N4 S! Y4 C" `( {% | - db.things.find({j : {$gte: 4}});
复制代码 ) D. f' x, ~6 }! E( N
也可以合并在一条语句内: - db.collection.find({ "field" : { $gt: value1, $lt: value2 } } ); // value1 < field < value
复制代码 5 O* X- A4 j L$ [
- L1 v$ m/ A/ l9 A, a8 A
0 h. {0 I% L) }+ i, V; w0 |4 Q2) 不等于 $ne 例子: - db.things.find( { x : { $ne : 3 } } );
复制代码
" E% G2 a V5 Q6 f; ]; e4 [3) in 和 not in ($in $nin)8 \) ^% j' h ?' A" A( c
: N7 Y8 u6 E; r* D. A( r语法: - db.collection.find( { "field" : { $in : array } } );
复制代码
2 n9 U$ Z9 M: `2 w例子: - db.things.find({j:{$in: [2,4,6]}});
( C9 ]* w3 q# m8 J, y1 y - db.things.find({j:{$nin: [2,4,6]}});
复制代码 ; [: f! c8 ^. c4 h% k* _( e& f, T
. O& N) a {( H4) 取模运算$mod
9 L0 W6 C* T7 G( n+ I
- j2 G: }8 M1 _) b2 P7 U& |8 f如下面的运算:
- db.things.find( "this.a % 10 == 1")
复制代码 ) Q5 f. x" d2 Y" Z$ c
可用$mod代替: - db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
! S' T$ k! }1 s9 u2 ~% D4 S
' \2 M9 {& C) K$ r5) $all
4 m; j- E4 A0 G) B8 h
: v5 C; D8 X' Z) u; w1 L7 b$all和$in类似,但是他需要匹配条件内所有的值:
2 @0 p0 }. r1 t$ j8 X
/ R' S" j V$ Q7 t; S, t3 X' _如有一个对象:
0 T9 c, z* J" f
8 m( P1 [- C: S1 s下面这个条件是可以匹配的: - db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码 , i* }- N: l8 Q) z- K' H8 _
但是下面这个条件就不行了: - db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
: k6 Z* }6 U$ u% |6 O2 A/ w5 V& b. k" K$ w3 u% k; u4 v
6) $size* V" ^, [& ?* S* i: c
" p5 B9 R# x* i! ?% F6 W- I0 `0 V% \
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
& D: _, C$ c9 ]: c: @) l* R& P- Q. x# e( A' m
下面的语句就可以匹配: - db.things.find( { a : { $size: 1 } } );
复制代码 5 N: c7 A- Z% y5 @& Z r) N
官网上说不能用来匹配一个范围内的元素,如果想找$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 c+ I* s& z! u; v$ x7)$exists $exists用来判断一个元素是否存在: 如: - db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
: c, a9 H" k3 Z* {- T1 V - db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码 , O8 l8 N# N5 y7 }2 l( U
8) $type $type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。 - db.things.find( { a : { $type : 2 } } ); // matches if a is a string
4 H, A4 V: Y8 A3 Z( {! O5 V - db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
& H5 R& `/ m6 `8 R' E1 G* t$ k9)正则表达式
v, E6 L J0 n+ W3 Y. V7 D2 M6 k. E, y
mongo支持正则表达式,如: - db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
) v. b/ E5 ?# B7 p4 |1 h10) 查询数据内的值+ f ~) J% V) E: T0 f8 t& U0 W
( b9 E3 w; R6 j- _+ ~* g8 `
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。 - db.things.find( { colors : "red" } );
复制代码 . u. }. d8 A0 }& U6 {
11) $elemMatch7 o7 Q0 @& h& n
: q- z5 o' e7 o如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素: - > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
2 V- t% L7 o/ y e/ o( G8 T r - { "_id" : ObjectId("4b5783300334000000000aa9"), * }& D( c! E$ t* I# U
- "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
) p3 l# L: Y2 H. W& I6 s2 K - }
复制代码
8 t! L" u+ t8 O. U( w8 u/ T$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。注意,上面的语句和下面是不一样的。 > t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )) s8 [+ q8 i; n* L" _
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
8 w% w- D2 x5 J( m: x; O
# C9 P8 r' j$ G12) 查询嵌入对象的值 - db.postings.find( { "author.name" : "joe" } );
复制代码
5 m1 t% ?" {3 ^% U+ ?, @9 Z7 A举个例子: - > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
6 _' e/ P5 j$ }( o+ m( ]如果我们要查询 authors name 是Jane的, 我们可以这样: - > db.blog.findOne({"author.name" : "Jane"})
复制代码
7 v7 b+ z6 o+ C3 x& d. @2 B* d) Y如果不用点,那就需要用下面这句才能匹配: - db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
2 I9 w/ O1 J5 S% Y+ C下面这句: - db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码 - t0 e; H+ u& s: o' d& G
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
c. ?" l S/ p) i- t. x13) 元操作符 $not 取反 如: - db.customers.find( { name : { $not : /acme.*corp/i } } );
: e0 h" y+ s. C5 B* Q- ^ - db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
2 g, y, ~5 j4 p( Vshell 环境下的操作: 1. 超级用户相关: 1. #进入数据库admin
& W3 b, B! B8 s/ S" _+ K( Z E$ c' k& P
2. #增加或修改用户密码 3. #查看用户列表 4. #用户认证
4 w# a3 O. E) k2 D) P; } U 5. #删除用户 6. #查看所有用户 7. #查看所有数据库 ( ]$ H* [+ |/ ^$ n5 A( S/ M
8. #查看所有的collection 9. #查看各collection的状态 - db.printCollectionStats()
复制代码
6 z3 t4 C7 ^6 Z8 y, | 10. #查看主从复制状态 - db.printReplicationInfo()
复制代码
" |! r l, W% Q. Q 11. #修复数据库 12. #设置记录profiling,0=off 1=slow 2=all 6 [2 T2 W4 Z0 d3 J: T$ {' B
13. #查看profiling
6 T2 E7 W: H/ C! z4 @7 x. T. O3 {+ \ 14. #拷贝数据库 - db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
. O; g, V: Z9 x' M 15. #删除collection
. Q( ~& e5 ^& X; E) q, g* I+ |& { 16. #删除当前的数据库
$ ~" P% y. h# ^# ?" V: \$ R* |6 ~: [ Y 2. 增删改 1. #存储嵌套的对象 - db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
4 |- y# p& X' T7 ` 2. #存储数组对象 - db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
. y+ w. }- |, l1 m5 i; h# B5 \7 w 3. #根据query条件修改,如果不存在则插入,允许修改多条记录 - db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码 % ~, r, B$ g. n
4. #删除yy=5的记录
2 y) h5 v! C) ]3 H( g$ T/ ? 5. #删除所有的记录
% v7 O5 \3 x8 A- B" W1 _! w" w 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() * C+ \! R/ o9 k5 o( Q
6. 高级查询 条件操作符 % W: z6 x; D" X0 @
- $gt : >
4 T) C4 S2 J1 ? - $lt : < 1 G# B% P n2 }6 Q+ M5 c
- $gte: >=
: ?, w+ L8 B0 Z6 `# T E - $lte: <= 6 }* N3 e; K5 [- Z
- $ne : !=、<>
* v4 g& m9 U9 N6 A - $in : in
* R' J m6 F- I) m, m- E - $nin: not in
- }. L% s/ S! {, J' f" g y, ^ - $all: all # O5 s- K2 I4 T. x* \6 J
- $not: 反匹配(1.3.3及以上版本)
复制代码 - x7 l" y) d7 ^3 S0 v& q" K- |
: _ L+ W( R/ f0 `$ i b8 r查询 name <> "bruce" and age >= 18 的数据
6 X# T3 j( R7 l- F- db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码 . I7 g+ Y3 r, H9 x5 @
) I* U2 ^" ], M0 P查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
8 T9 [% d6 a# A" Z! C* S8 Q c6 Z% K- db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码 , q! A; p7 P# h" f: B( r
' [# R8 y% \9 ^( H, @ I查询 age in (20,22,24,26) 的数据
% [, I2 e3 C$ _( J4 G: F9 n- db.users.find({age: {$in: [20,22,24,26]}});
复制代码 0 O- ~: ~& S" E/ a) `
b! b7 O! {$ W D% Z查询 age取模10等于0 的数据 : |5 F1 W; [9 _, P; R+ v( c/ x3 W- k
- db.users.find('this.age % 10 == 0');
复制代码
& \: w. u, B/ t1 X4 J, f+ @" L或者
4 Q& j( K H, B6 D" V- db.users.find({age : {$mod : [10, 0]}});
复制代码
/ \7 i5 }$ H/ K0 B6 ?4 A* T- }- {4 M1 `) ` ]2 v8 s* `
匹配所有 m& W1 z3 h8 Z* E7 @2 U. I7 `
- db.users.find({favorite_number : {$all : [6, 8]}});
复制代码 9 g V" n2 F7 a* L+ Q
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
7 ^9 ^5 e2 Y2 H7 r) A. A' Q可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 5 c) R! @# T. f
. e$ ]3 {3 b! P/ ]- Z0 p8 k2 E查询不匹配name=B*带头的记录
# t5 P6 U a' x' Q" l) Q0 V2 ]- db.users.find({name: {$not: /^B.*/}});
复制代码
7 F3 C# h& A2 B; I9 E1 B查询 age取模10不等于0 的数据
. z7 z, D7 l! T2 ^6 d4 y: ?8 Z- db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码 # y* q+ ~8 H8 ]0 A3 J! I* j
% O+ ?" L% |" v8 Y#返回部分字段 " c% B# R& N. j! C* d2 S
选择返回age和_id字段(_id字段总是会被返回) ; l8 v% G6 f* t) D( f$ c% R; J% a
- db.users.find({}, {age:1}); / }) Z( m* U$ u
- db.users.find({}, {age:3});
: I0 Q$ O& ^' E3 o3 t8 n - db.users.find({}, {age:true});
3 X/ @7 g( m0 p0 p3 v5 C. e+ d - db.users.find({ name : "bruce" }, {age:1});
复制代码 , v1 c+ r. b2 G7 v
0为false, 非0为true 4 P& y Y4 K8 k3 \) K. K
3 [6 V+ k, M2 j! D w- k1 n" `2 Y选择返回age、address和_id字段 6 O9 P7 {% P; E% j# L/ S
- db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
4 |8 {$ D$ c- v% [
( O3 b. L& ~ K* g排除返回age、address和_id字段
8 R5 b& e) F- k7 ?- db.users.find({}, {age:0, address:false});
, P) j. D; q3 _* R1 | - db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
# ]& q) `1 _1 w o) p6 A' r
. C5 A l, L( ^: Q4 a% K# ~数组元素个数判断
. |' a: U" [1 ^3 K5 _对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
; ~5 x3 Z) U2 W; E- n匹配db.users.find({favorite_number: {$size: 3}}); ; ^& r: m( W, d4 z/ m
不匹配db.users.find({favorite_number: {$size: 2}});
7 p0 m) F1 [6 `/ y4 s+ C' O9 _6 [# Q* r2 p1 b
$exists判断字段是否存在
0 W; ~7 [6 ^+ {7 a! D' d查询所有存在name字段的记录
3 q+ x" s. ~$ t# d9 c7 M5 v; j- db.users.find({name: {$exists: true}});
复制代码
d; B' n- h9 R查询所有不存在phone字段的记录
! K) a8 N! K7 P% e# _8 G) u4 p- db.users.find({phone: {$exists: false}});
复制代码
! d5 l" o) e5 |% l4 y/ l
@8 k% M3 K9 ?# L/ F O$type判断字段类型
& Y1 P0 b/ w/ q# g7 h4 ~) r3 o查询所有name字段是字符类型的
* S2 X: ~) ?3 g% s- db.users.find({name: {$type: 2}});
* a2 G( l# l: a5 }* X3 b8 A
复制代码 ' ~) Y0 w7 b$ ]7 b
查询所有age字段是整型的 5 [0 j) q+ N8 _' G* @
- db.users.find({age: {$type: 16}}); , l+ g8 P9 Z1 b4 K3 n
复制代码
5 q0 F' r1 z6 T. y9 J0 z% z对于字符字段,可以使用正则表达式
! M" [. y0 k; b, J查询以字母b或者B带头的所有记录
9 h& w* V; |* `- db.users.find({name: /^b.*/i});
# e! \; O8 w) C0 _- e- `
复制代码 Z" ~) p5 Y8 g& S
$elemMatch(1.3.1及以上版本) " `) u3 V* c; n: H1 Y
为数组的字段中匹配其中某个元素 " @ l$ S3 V' ~' j+ X' ]
$ i: u C6 I" q- p. [7 T( C! WJavascript查询和$where查询 , I7 M9 P* e4 z3 R8 T- j- D
查询 age > 18 的记录,以下查询都一样 & B m3 m) _7 p h& ~( V* c
- db.users.find({age: {$gt: 18}}); . L# {' M" G& n1 ~
- db.users.find({$where: "this.age > 18"});
6 |0 a6 C8 N* m - db.users.find("this.age > 18"); + {4 S: c% p, s7 M' t% Q
- f = function() {return this.age > 18} db.users.find(f);
复制代码
% o" e% p$ w% {- E3 i- ~) Z; I
) {# \, u) f3 r, o; g排序sort()
0 z6 k7 J( {4 e5 i5 ?以年龄升序asc
/ U" s1 L3 E& t4 l0 ^( c- db.users.find().sort({age: 1});
( {; f% j% l9 W; L/ N$ R; V7 O
复制代码
- z' E/ T7 r- C+ J以年龄降序desc " d! e2 Q3 I# r
- db.users.find().sort({age: -1}); 1 a8 m3 d2 O0 \% w( \7 y# Y* X
复制代码 6 Y2 n! K9 m/ m. t1 N5 L' f
限制返回记录数量limit() 2 e. \* v3 f6 s; e1 C- G0 A1 b
返回5条记录 " S6 @$ m! R `, c
- db.users.find().limit(5); + `8 A7 [) }$ y. J6 e0 |
复制代码 4 _% D6 P$ \' B. ]) K( s
返回3条记录并打印信息 2 X/ |, y0 e% T6 G: @
- db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); ) U9 G2 o( E( w+ r* K$ C: K
复制代码
" z- |# h. ]- u, B' C0 J. P结果 3 H, w( j$ j6 W# ~; E+ ^. U, t/ Z
- my age is 18 . {2 N: z; ~; {7 g4 X% Q* o% y' Y
- my age is 19 : F8 y+ i0 ?, A7 H
- my age is 20
复制代码 ; f3 p$ `# H( D. T0 c
9 k6 w" A* i c; S, d+ m限制返回记录的开始点skip() , H6 ~* y0 F: W0 u
从第3条记录开始,返回5条记录(limit 3, 5)
2 K0 O$ ^5 p. x" h/ a- db.users.find().skip(3).limit(5); n, R5 M$ L! K h4 }4 s
复制代码
+ o& e7 L) y( M8 M查询记录条数count() & Z" C1 d e* \- H/ y( d9 u
db.users.find().count(); , ~& P& f1 B" C5 i4 Y# |$ v; O3 w
db.users.find({age:18}).count(); 6 R3 q; Y* X5 @' Z
以下返回的不是5,而是user表中所有的记录数量 2 w D3 n" M5 g6 L3 I% v; L. J0 n
db.users.find().skip(10).limit(5).count(); $ o, e) }1 S2 [1 e+ D4 T* u1 B
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 9 q2 i) v2 i1 E" ?
- db.users.find().skip(10).limit(5).count(true);
复制代码 9 ^' l T3 E# S
. h" G' M, {/ Z. j分组group() / ]0 b2 x7 ^2 X% `" S1 ^
假设test表只有以下一条数据
8 o+ ?6 Q$ {2 P; x2 e3 O) C- { domain: "www.mongodb.org" 7 J3 {$ n3 t* c% P& \: O* E; f
- , invoked_at: {d:"2009-11-03", t:"17:14:05"} 3 f+ `7 A9 Q% J. I! X* d' _7 N
- , response_time: 0.05 * o' z1 x5 Z% y( Y0 u0 _4 Z
- , http_action: "GET /display/DOCS/Aggregation" 2 o: ^( ?$ B0 I4 R% i2 F
- }
复制代码 ( f7 y6 @2 H* Q
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; , a/ B$ q4 R; Y0 d
- db.test.group(
- C8 d: c' z5 V+ E! Z/ M! y - { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
% q- u& l* L+ x9 | y# O( I; R - , key: {http_action: true}
3 c* f# U2 @! v - , initial: {count: 0, total_time:0}
/ [. P) d* P; m: F# v! y - , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
3 L, A" Y) K2 t, u- M - , finalize: function(out){ out.avg_time = out.total_time / out.count }
/ u* c; c/ ?* S q+ ` - } );
. Z: }7 `: k0 T4 a' F) h2 e - 7 C2 S3 d! ^& _
- [ # J! U+ {4 }1 ]: L, c: E
- { ! G6 a+ v: |; P6 t4 }& V$ ~" g
- "http_action" : "GET /display/DOCS/Aggregation",
7 h( w$ C9 _# s* S+ k8 X - "count" : 1,
' t% s# x8 x# V" O$ j - "total_time" : 0.05,
+ T/ i6 w) N9 M* F5 W. \ - "avg_time" : 0.05 , H. q7 X* _5 d& s( E6 v1 O0 V# i
- }
2 a4 p* X, m9 l& |+ r+ v0 w5 ~ - ]
复制代码
! V. {8 L6 X0 ]0 ~ q8 Z; Q4 p( E( N* Y8 a* k
: l0 O! Q+ K& o
MongoDB 高级聚合查询MongoDB版本为:2.0.8 系统为:64位Ubuntu 12.04 先给他家看一下我的表结构[Oh sorry, Mongo叫集合] 如你所见,我尽量的模拟现实生活中的场景。这是一个人的实体,他有基本的manId, manName, 有朋友[myFriends],有喜欢的水果[fruits],而且每种水果都有喜欢的权重。 很不好的是你还看见了有个“_class”字段? 因为我是Java开发者, 我还喜欢用Spring,因此我选用了Spring Data Mongo的类库[也算是框架吧,但是我不这么觉得]。 现在有很多人Spring见的腻了也开始烦了。是的,Spring野心很大,他几乎想要垄断Java方面的任何事情。没办法我从使用Spring后就离不开他,以至于其他框架基本上都不用学。我学了Spring的很多,诸如:Spring Security/Spring Integration/Spring Batch等。。。不发明轮子的他已经提供了编程里的很多场景,我利用那些场景解决了工作中的很多问题,也使我的工作变得很高效。从而我又时间学到它更多。Spring Data Mongo封装了mongodb java driver,提供了和SpringJDBC/Template一致编程风格的MongoTemplate。 不说废话了,我们直接来MongoDB吧。 - Max 和Min7 g& D( h2 S5 S3 Q
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。 要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。 如我的例子,我想取得集合中年龄最大的人。 - db.person.find({}).sort({"age" : -1}).limit(1)
复制代码 # U. n, v2 J5 U, z8 m \* ^
2 A H- d+ x. c! i
2 g u5 x% }7 G% ?0 X+ _# o9 f8 y相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。 当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。 - distinct
& ~: A d; E% F& {- j) b
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits]. 如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。 如上面的表结构,我想统计所有的喜欢的水果。 - db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
$ i' ]$ i& Y1 e& X! n7 d) }: `8 U0 ?" l, F! r6 y
他成功执行了。输出如: - [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
r) J+ ^7 W5 C$ U+ U
7 y+ }% m* x" ] g2 H+ [4 S5 l 我想统计集合中共有多少个人[按名字吧] - db.person.distinct("manName")
复制代码 / n9 E7 L) b p C, E- S
: w7 Y4 j2 u' i5 f, B
我想统计指定个数的人的共同关注的朋友。 - db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
, a5 x B$ s& R1 L. H3 C
+ s9 m* \1 k3 e. |/ o 输出如: - ( k7 X7 n0 d4 W2 |1 ^% _; L/ l
- [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码 $ \9 M8 r% O0 Q% K8 y
8 J5 ]6 ~& S+ g4 m K( H( D! q9 X4 i# F
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的? Spring Schema: - <beans xmlns="http://www.springframework.org/schema/beans"1 H# w+ M& q! t, y$ E9 J m
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"5 K: [0 d# x, K. ~3 _' ?, F. A
- xmlns:context="http://www.springframework.org/schema/context"9 y- C% p0 G- B$ h; P- H
- xmlns:mongo="http://www.springframework.org/schema/data/mongo"0 B0 n5 b: d, K1 j1 x
- xsi:schemaLocation="http://www.springframework.org/schema/beans
* x- H( S8 ~7 C - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd3 }6 R& f1 ~ I [
- http://www.springframework.org/schema/context! n% t8 ], W! b9 h8 e; }! p
- http://www.springframework.org/schema/context/spring-context-3.1.xsd
: {+ [9 k: ` g2 M7 K1 e - http://www.springframework.org/schema/data/mongo
( l# T/ _# {4 b t- [ - http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
* j. H: c1 g5 Q -
) O5 [6 I4 A' m9 N6 d2 k% V - <context:property-placeholder location="classpath:mongo.properties" />
/ J. ^2 r, ]8 x: c9 u -
: J( |# _( O4 L& V- T - <!-- Default bean name is 'mongo' -->6 L0 I4 E7 r3 o. P* d1 ? |6 r) Z
- <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
- G* V0 E! u* j -
- o/ N: K1 N- I7 S - <mongo:db-factory id="mongoDbFactory"
; G+ P K* y+ S( Q" i' T! z. { - mongo-ref="mongo"
5 L9 n2 d/ h* ]% Y% T k - dbname="mongotest" />
* l D. |- o- ]. i6 ^: [ -
|7 F; L4 u3 T7 J0 r- E - <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">0 l) r' U$ O$ i6 K% l
- <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
* \2 o; s, C% B! M. y; ?* \ - </bean>% N7 e2 y; D$ T
- </beans>
复制代码
6 J) }7 S; e0 s2 T+ P
, x9 d9 J1 ?' w& Y max和min的测试: - @Test
8 o( E" ?8 f8 E+ _6 |3 F - public void testMaxAndMinAge() throws Exception {
5 t2 Y3 ^8 H) h# o9 A8 H - Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);9 P; B) X4 ]( r: u1 T7 I
- Person result = mongoTemplate.findOne(q, Person.class);; m0 J0 _# }' W! {8 N# s
- log.info(result);) G& Q( k/ S6 n. c
- $ s& s/ ~3 s" T; X' x
- q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
; z M" S) B3 n - result = mongoTemplate.findOne(q, Person.class);( P2 j3 n6 w8 A y
- log.info(result);! U( r5 Q" M! @4 d3 ^
- }
复制代码 5 W6 P+ Q6 Z& }
; s, a4 y. P* J/ f distinct的测试: - @Test& z0 p/ u+ u/ S6 z. Z4 c- Q
- public void testDistinct() throws Exception {
9 \! H+ l7 R+ T3 \ - List result = mongoTemplate.getCollection("person").distinct("myFriends");1 z1 J+ v9 Q5 X/ L- p7 x* x) s! Q
- for (Object o : result) {
- ~3 F# V; @; y) B3 L4 a. K - log.info(o);
3 L) H" r) a; j - }
; j3 _. X6 \2 E% z: a4 E0 w. Q - 4 g& ?- O4 g( U2 c/ w) X! A6 C; c
- log.info("==================================================================");* R) {$ n) G" X; q/ j; F9 b: z
- Query query = Query.query(Criteria.where("manId").is("123456"));& D- A8 S& z$ Q7 y1 v
- result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());* E6 x; y# N& w0 k' T; z
- for (Object o : result) {9 h1 j3 p( j1 o& \; S9 A
- log.info(o);1 G4 x& T F( ?2 ~
- }
& G. M/ @$ d) g1 b& B q0 q -
4 v: i5 f! ?* Q x9 l - log.info("==================================================================");: ~. h" Y- @9 j3 b* F" I$ u* j% C6 U
- result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");$ Z$ T2 B% j) C K( b
- for (Object o : result) {
6 ~& Z" P; \, g. F/ j$ A - log.info(o);
" ~* n, |- P3 c! Q* G1 J! u - }
& |5 Q. A4 E0 W$ }" K - }
复制代码 : U6 t' V3 c/ \/ Y7 W a
5 E' l' t8 A8 Z' X! a
输出的结果为: - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
% g/ I9 q7 C0 G0 Z7 @/ M: t - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 3456784 ?5 g3 x! F1 {- a
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789: x# C& G! j8 s: _
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876543 p& A* T& v. F) R/ X/ P: b
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni0 |/ `3 U: b) \# z+ ^7 Q
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo+ X$ H% N# E) l4 `8 c) G* p+ g
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456 G/ ~" |+ T" n8 x
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================& M1 r+ l$ w- | z3 ]. j+ X
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567, U: R7 B% |5 w9 n1 z
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
* d7 a) O/ X4 r4 |$ m# `: ] - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
( {6 l/ y3 _" C# n+ E) B - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
( F {" M* ~! ~5 X8 M9 `7 n& b - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
3 X, k! W0 j* j5 w - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
- t1 \! Z- ^8 [; H6 S - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
- p1 C Z, Y! }* J( m; I - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc4 T ?0 w8 U7 i
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
' x5 v }- N o7 G: ~5 ~ - 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx. j& T( P% a8 s
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy- T5 x; Z& G6 y) M6 B# v* `
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz# U: k' G, }% W3 d& @+ y2 N
- 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
) M4 a; j9 Y: L8 i& Z1 W0 P" S* D, i - 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
复制代码
6 c) f M+ l7 y. B9 g1 |* h
* }( _0 G0 k4 i; X2 u5 ]$ ^ 这里我要特别说明一下, 当使用了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等信息。 - m1 c' \: W4 l5 E, Q
0 p) p- J1 R6 h# E& @% o0 \; j3 ]# N! H
|