MongoDB学习笔记(十三):SpringData-Mongodb

最完整原版教程:http://docs.spring.io/spring-data/data-mongo/docs/1.4.0.RELEASE/reference/html/mongo.core.html 
范例中的MetaDBMongoFactory是我自己写的,你也可以通过Spring配置文件获得。如下 
http://www.blogjava.net/wangxinsh55/archive/2012/03/29/372987.html 

1.单表增删查改 
@Id - 文档的唯一标识,在mongodb中为ObjectId,它是唯一的,通过时间戳+机器标识+进程ID+自增计数器(确保同一秒内产生的Id不会冲突)构成。 
@Document - 把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。 
@DBRef - 声明类似于关系数据库的关联关系。ps:暂不支持级联的保存功能,当你在本实例中修改了DERef对象里面的值时,单独保存本实例并不能保存DERef引用的对象,它要另外保存,如下面例子的Person和Account。 
@Indexed - 声明该字段需要索引,建索引可以大大的提高查询效率。 
@CompoundIndex - 复合索引的声明,建复合索引可以有效地提高多字段的查询效率。 
@GeoSpatialIndexed - 声明该字段为地理信息的索引。 
@Transient - 映射忽略的字段,该字段不会保存到mongodb。 
@PersistenceConstructor - 声明构造函数,作用是把从数据库取出的数据实例化为对象。该构造函数传入的值为从DBObject中取出的数据。 
文档版本: @Version (建议用Long) 

范例: 
新建实体:

01. public class User
02. {
03. @Id  
04. private ObjectId id;  
05. @Indexed(unique = true)  
06. private String ssn;
07. @Indexed  
08. private String userName;  
09. private String password;
10. private Integer age;  
11. @Transient  
12. private Integer accountTotal;  
13. //其它set,get略......
14. }

增删查改

01. public void testCurd()
02. {
03. MongoTemplate template = MetaDBMongoFactory.getInstance().getMongoTemplate();
04. User user = new User();        
05. user.setSsn(...);//唯一性内容
06. user.setPassword("123456");
07. user.setUsername("张三");
08.  
09. //增加
10. template.save(user);
11. System.out.println("1. user : " + user);
12.  
13. //查询
14. Query searchUserQuery = new Query(Criteria.where("username").is("张三"));
15. User savedUser = template.findOne(searchUserQuery, User.class);
16. System.out.println("2. find - savedUser : " + savedUser);
17.  
18. //修改
19. template.updateFirst(searchUserQuery, Update.update("password", "45678"), User.class);
20. User updatedUser = template.findOne(searchUserQuery, User.class);
21. System.out.println("3. updatedUser : " + updatedUser);
22.  
23. //删除
24. template.remove(searchUserQuery, User.class);
25. List listUser = template.findAll(User.class);
26. System.out.println("4. Number of user = " + listUser.size());
27. }

在看个更多功能的实体类

01. @Document(collection="person")  
02. @CompoundIndexes({  //组合索引
03. @CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")  
04. })  
05. public class sample {  
06.  
07. @Id  
08. private String id;  
09. @Indexed(unique = true)  
10. private Integer ssn;  
11. private String firstName;  
12. @Indexed  
13. private String lastName;  
14. private Integer age;  
15. @Transient  
16. private Integer accountTotal;  
17. @DBRef  
18. private List accounts;  
19.  
20. .....set and get
21. }

 

2.关联方式1:DBRef 一对一,一对多 
多对多就是对方表也放个list一起保存呗 

User.java

01. public class User
02. {
03. @Id
04. private ObjectId id;
05. @Indexed
06. private String name;
07. private Integer age;
08. @DBRef
09. private Weapon weapon;//一对一
10. @DBRef
11. private List items;//一对多
12. //set,get略......
13. }

Weapon.java

1. public class Weapon
2. {
3. @Id
4. private ObjectId id;
5. private String name;
6. private int power;
7. //set,get略......
8. }

Item.java

1. public class Item
2. {
3. @Id
4. private ObjectId id;
5. private String name;
6. private String desc;
7. //set,get略......
8. }

添加:

01. private voidsave()
02. {
03. MongoTemplate template = MetaDBMongoFactory.getInstance().getMongoTemplate();
04.  
05. User user = new User();
06. user.setName("张三");
07. user.setAge(30);
08.  
09. List items = new ArrayList();
10. for (int i = 0; i < 10; i++)
11. {
12. Item item = new Item();
13. item.setName("道具" + i);
14. item.setDesc("描述");
15. template.save(item);
16. items.add(item);
17. }
18.  
19. Weapon weapon = new Weapon();
20. weapon.setName("武器");
21. weapon.setPower(99);
22. template.save(weapon);
23.  
24. user.setWeapon(weapon);
25. user.setItems(items);
26. template.save(user);
27. }

查询 
一对多的对象会全部拿出来,所以如果关联的对象特别多超过几千,请用lazy=true的方式,懒惰加载

1. User user = template.findOne(new Query(Criteria.where("id").is(id)), User.class);

DBRef查询

1. ObjectId id = user.getId();Weapon myWeapon = template.findOne(new Query(Criteria.where("name").is("武器1")),Weapon.class);
2. Query query = new Query(Criteria.where("id").is(id).and("myWeapon").is(myWeapon));
3. User queryResult = template.findOne(query, User.class);

DBRef原生查询

1. Query query = new BasicQuery("{'id':'"+id.toString()+"', 'weapon' : {'$ref':'weapon','$id':{'$oid':'52e9affffad134ac3ee2e02a'}} }");
2. User queryResult = template.findOne(query, User.class);

排序

1. Query query = new Query(Criteria.where("id").is(id));
2. query.with(new Sort(Sort.Direction.DESC, "name"));
3. ......

分页,表示每页最多10条,从第3页开始

1. Query query = new Query(Criteria.where("id").is(id));
2. query.limit(10);
3. query.skip(20);

懒惰加载(1.4.0新功能,棒极了,大大提高效率)

1. @DBRef(lazy = true)
2. private List myItems;//一对多

 

3.关联方式2:集合属性 
比起DBRef模式的好处在于通过elemMatch能查询过滤。但缺点就是数据冗余。 
表字段性除了基本属性,还可以是任何对象,Map,List,这点是关系数据库做不到的。 

范例是获取用户信息,并且只取出名字是道具1的道具,如果道具特别多,这种写法可以有效加强性能

01. public class User
02. {
03. @Id
04. private ObjectId id;
05. @Indexed
06. private String name;
07. private Integer age;
08. private List items;
09. }

查询:

1. Query query = new Query(Criteria.where("id").is(id));
2. query.fields().include("items").include("name").elemMatch("items",Criteria.where("name").is("道具1"));
3. User user = template.findOne(query, User.class);

.include("items").include("name")表示查询结果集只需要这2列数据,这种做法可以减少读取的io字节大小 
elemMatch是过滤返回的items是一部分而不需要全部

 

4.聚合查询 

1).分组Group

1. GroupByResults results =  template.group("user", GroupBy.key("age").initialDocument("{ count: 0 }").reduceFunction("function(doc, prev) { prev.count += 1 }"), XObject.class);

最后结果集里,比如看到,但最多只能处理2万条数据 
"retval":[{"age":13.0,"count":2.0},{"age":14.0,"count":1.0},{"age":30.0,"count":33.0}],"count":36.0 


2).MapReduce统计

1. MapReduceResults asd = template.mapReduce("user", "function(){emit( this.id , { count : 1 } )}",
2. "function(key, values){var total=0;values.forEach(function(val){total += val.count;});return {count : total};}", User.class);

3).Aggregation 
范例是统计User每个用户多少条记录,类似于oracle的group

1. class UserStats {
2. String id;
3. Integer totalCount;
4. //其它set get
5. }
1. import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
2. Aggregation agg = newAggregation(
3. User.class,
4. group("name").count().as("totalCount"),
5. sort(Sort.Direction.ASC, previousOperation(), "totalCount"),
6. match(new Criteria(.....))//过滤条件
7. );
8. AggregationResults aggregateResult = template.aggregate(agg, "user", UserStats.class);

结果集: 
"mappedResults":[{"id":"方佳玮","totalCount":12}]

 

5.副本集群模式下,读写分离 

统一配置:

1. template.setReadPreference(ReadPreference.nearest());
2. Weapon myWeapon = template.findOne(new Query(Criteria.where("name").is("武器1"))

原生Api

1. DBObject dbObject = coll.findOne(object, null , preference);

说明: 
primary:默认参数,只从主节点上进行读取操作; 
primaryPreferred:大部分从主节点上读取数据,只有主节点不可用时从secondary节点读取数据。 
secondary:只从secondary节点上进行读取操作,存在的问题是secondary节点的数据会比primary节点数据“旧”。 
secondaryPreferred:优先从secondary节点进行读取操作,secondary节点不可用时从主节点读取数据; 
nearest:不管是主节点、secondary节点,从网络延迟最低的节点上读取数据。

 

 

 

6.文件读写(Gridfs)

 

01. public void save(File file, String fileName) throws FileNotFoundException
02. {
03. GridFsTemplate gridFsTemplate = MetaDBMongoFactory.getInstance().getGridFsTemplate();
04. MongoTemplate template = MetaDBMongoFactory.getInstance().getMongoTemplate();
05. SinitekFiles sinitekFiles = new SinitekFiles();
06. sinitekFiles.setDesc("描述");
07. gridFsTemplate.store(new FileInputStream(file), fileName,sinitekFiles);
08. }
09.  
10. public GridFSDBFile query(String fileName) throws FileNotFoundException
11. {
12. GridFsTemplate gridFsTemplate = MetaDBMongoFactory.getInstance().getGridFsTemplate();
13. return gridFsTemplate.findOne(Query.query(Criteria.where("filename").is(fileName)));
14. }
下面是原生api方式
1. DB db = mongoDbFactory.getDb();  
保存文件(其中FS_NAME相当于gridfs文件系统的表名,可以有多个)
01. public boolean saveFile(File file, String fileName, String contentType,
02. DBObject metaData) {
03.  
04. GridFSInputFile gfsInput;
05. try {   
06. gfsInput = new GridFS(db, FS_NAME).createFile(file);
07. gfsInput.setFilename(fileName);
08. gfsInput.setContentType(contentType);
09. gfsInput.setMetaData(metaData);
10. gfsInput.save();
11. } catch (IOException e) {
12. log.error(e, e);
13. return false;
14. }
15. return true;
16. }
通过文件名读取文件
01. public GridFSDBFile findFileByName(String fileName){
02. GridFSDBFile gfsFile ;
03. try {      
04. gfsFile = new GridFS(db, FS_NAME).findOne(fileName);
05. } catch (Exception e) {
06. log.error(e, e);
07. return null;
08. }
09. return gfsFile;
10. }
通过id读取文件
01. public GridFSDBFile findFileById(String id){
02. GridFSDBFile gfsFile ;
03. try {      
04. gfsFile = new GridFS(db, FS_NAME).find(new ObjectId(id));
05. } catch (Exception e) {
06. log.error(e, e);
07. return null;
08. }
09. return gfsFile;
10. }
输出文件到OutputStream
查看
打印 ?
01. private boolean writeToOutputStream(OutputStream out, GridFSDBFile gfsFile) {
02. try {     
03. gfsFile.writeTo(out);
04. } catch (IOException e) {
05. log.error(e, e);
06. return false;
07. }
08. return true;
09. }

 

 

 

 

 

7.文件读写(Document)

 

我偷懒范例选自网络,用的原生api,估计spring momgodb也差不多  

保存:
01. public static void main(String[] args) {
02. try {
03. Mongo mongo = new Mongo();
04. DB db = mongo.getDB("company");
05. DBCollection collection = db.getCollection("userinfo");
06. BasicDBObject employees = new BasicDBObject();
07. File file = new File("d://shuimohua01.jpg");
08. FileInputStream input = new FileInputStream(file);
09. byte[] files = new byte[input.available()];
10. while (input.read(files)>0) {
11. input.read(files);
12. }
13. input.close();
14. employees.put("no", "1015");
15. collection.remove(employees);
16. employees.put("member", files);
17. employees.put("filename", file.getName());
18. System.out.println(files.length);
19. collection.insert(employees);
20. } catch (UnknownHostException e) {
21. // TODO Auto-generated catch block
22. e.printStackTrace();
23. } catch (MongoException e) {
24. // TODO Auto-generated catch block
25. e.printStackTrace();
26. } catch (FileNotFoundException e) {
27. // TODO Auto-generated catch block
28. e.printStackTrace();
29. } catch (IOException e) {
30. // TODO Auto-generated catch block
31. e.printStackTrace();
32. }
33. }
34. }
读取:
查看
打印 ?
01. public static void main(String[] args) {
02. try {
03. Mongo mongo = new Mongo();
04. DB db = mongo.getDB("company");
05. DBCollection collection = db.getCollection("userinfo");
06. DBObject employees = new BasicDBObject();
07. employees.put("no", "1015");
08. employees = collection.findOne(employees);
09. byte[] files = (byte[]) employees.get("member");
10. ByteArrayInputStream input = new ByteArrayInputStream(files);
11. File f = new File("e://" + employees.get("filename"));
12. FileOutputStream output = new FileOutputStream(f);
13. byte[] b=new byte[input.available()];
14. while (input.read(b)>0) {
15. input.read(b);
16. output.write(files);
17. }
18. input.close();
19. output.close();
20. } catch (UnknownHostException e) {
21. // TODO Auto-generated catch block
22. e.printStackTrace();
23. } catch (MongoException e) {
24. // TODO Auto-generated catch block
25. e.printStackTrace();
26. } catch (IOException e) {
27. // TODO Auto-generated catch block
28. e.printStackTrace();
29. }
30. }
31. }

 

你可能感兴趣的:(nosql-mongodb)