Mongdb中存储数据关系--------1对多关系

来源:互联网 发布:56相册制作软件 编辑:程序博客网 时间:2024/06/10 05:37

          每次写技术分享文章太无聊,为了给自己不无聊,讲个子之鱼安之鱼之乐的典故,故事来自<庄子秋水>:

          庄子惠子游于濠梁之上。
  庄子曰:“儵(读音tiao二声,鲦)鱼出游从容,是鱼之乐也。”
  惠子曰:“子非鱼,安知鱼之乐?”
  庄子曰:“子非我,安知我不知鱼之乐?”
  惠子曰:“我非子,固不知之矣;子固非鱼也,子之不知鱼之乐,全矣。”
  庄子曰:“请循其本。子曰‘汝安知鱼之乐’云者,既已知吾知之而问我,我知之濠上也。”


以前不喜欢文言文,现在长大了,见识多了,读的书也多了,才发现古文其实没有那么多废话,简洁的话语,蕴藏了很多哲理。


接下来回到Mongdb中的一种常见关系中来。

MongoDB表中------关系型数据库中的1对多关系
    应用场景细化:在1对多的关系中,这个多究竟代表多少了?可能是几个,也可能是几万个,甚至是几E个。以下分为3个部分来讲解:


a.n代表很少的部分
    比如在person和address中,一个人物对应多个地址,我们采用嵌入式文档来建模。数据格式如下所示:


 

        用json数据表示就是:

{  "_id" : ObjectId("55da8c55e81f2e32285cbf4f"),  "_class" : "com.lgy.model.Person",  "name" : "feng",  "age" : 21,  "addresss" : [{      "street" : "武汉 0",      "tel" : 111    }, {      "street" : "武汉 1",      "tel" : 112    }, {      "street" : "武汉 2",      "tel" : 113    }, {      "street" : "武汉 3",      "tel" : 114    }, {      "street" : "武汉 4",      "tel" : 115    }]}
                      *上面的table表用的是MongDB的一个Client图形管理化工具,里面有Tree view , Table view    Text view,体验相当不错!

用java实现的原理如下:

Model层代码:

 

package com.lgy.model;import java.io.Serializable;import java.util.List;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.DBRef;import org.springframework.data.mongodb.core.mapping.Document;import org.springframework.data.mongodb.core.mapping.Field;@Document(collection="person")public class Person implements Serializable {private static final long serialVersionUID = -4477575782622566016L;@Idprivate String Id;private String name;private Integer age;private List<Address> addresss;public String getId() {return Id;}public void setId(String id) {Id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public List<Address> getAddresss() {return addresss;}public void setAddresss(List<Address> addresss) {this.addresss = addresss;}}package com.lgy.model;import java.io.Serializable;public class Address implements Serializable {private static final long serialVersionUID = -6403164299535570346L;private String street;private Integer tel;public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public Integer getTel() {return tel;}public void setTel(Integer tel) {this.tel = tel;}}


dao层代码:

package com.lgy.dao;import com.lgy.base.IBaseDao;import com.lgy.model.Person;public interface IPersonDao extends IBaseDao<Person> {}package com.lgy.dao;import org.springframework.stereotype.Repository;import com.lgy.base.BaseDaoImpl;import com.lgy.model.Person;@Repositorypublic class PersonDaoImpl extends BaseDaoImpl<Person> implements IPersonDao {}
            封装的IBaseDao和BaseDaoImpl在文章末尾给出。


测试类代码如下:

        @Testpublic void insert1Test() {List<Address> addresss = new ArrayList<Address>();for (int i = 0; i < 5; i++) {Address address = new Address();address.setStreet("武汉 " + i);address.setTel(111 + i);addresss.add(address);}Person p = new Person();p.setName("feng");p.setAge(21);p.setAddresss(addresss);personDao.save(p );}

优势:不需要执行单独的查询就可以获得某个Person下对应的所有Address信息
缺点:无法独立操作Address信息,必须先查询到Person文档湖,才有可能继续操作Address。




b.n代表好些个的部分
    比如在产品和零部件中,每个产品会有很多个零部件。我们可以才有引用方式来建模。 数据格式如下所示:

          

{  "_id" : ObjectId("55da9787e81fa872622983ea"),  "_class" : "com.lgy.model.Product",  "name" : "麦克维",  "parts" : ["55da9787e81fa872622983e5", "55da9787e81fa872622983e6", "55da9787e81fa872622983e7", "55da9787e81fa872622983e8", "55da9787e81fa872622983e9"]}/* 0 */{  "_id" : ObjectId("55da9787e81fa872622983e5"),  "_class" : "com.lgy.model.Part",  "name" : "haha0",  "cost" : 45.0}/* 1 */{  "_id" : ObjectId("55da9787e81fa872622983e6"),  "_class" : "com.lgy.model.Part",  "name" : "haha1",  "cost" : 46.0}/* 2 */{  "_id" : ObjectId("55da9787e81fa872622983e7"),  "_class" : "com.lgy.model.Part",  "name" : "haha2",  "cost" : 47.0}/* 3 */{  "_id" : ObjectId("55da9787e81fa872622983e8"),  "_class" : "com.lgy.model.Part",  "name" : "haha3",  "cost" : 48.0}/* 4 */{  "_id" : ObjectId("55da9787e81fa872622983e9"),  "_class" : "com.lgy.model.Part",  "name" : "haha4",  "cost" : 49.0}

java代码实现:

model层代码:

package com.lgy.model;import java.io.Serializable;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.Document;@Document(collection="part")public class Part implements Serializable {private static final long serialVersionUID = 4858632495675595186L;@Idprivate String id;private String name;private Double cost;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getCost() {return cost;}public void setCost(Double cost) {this.cost = cost;}}package com.lgy.model;import java.io.Serializable;import java.util.List;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.Document;@Document(collection="product")public class Product implements Serializable {private static final long serialVersionUID = 5316002024895759481L;@Idprivate String id;private String name;private List<String> parts;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<String> getParts() {return parts;}public void setParts(List<String> parts) {this.parts = parts;}}


dao层代码:

package com.lgy.dao;import com.lgy.base.IBaseDao;import com.lgy.model.Address;import com.lgy.model.Person;import com.lgy.model.Product;public interface IProductDao extends IBaseDao<Product> {}package com.lgy.dao;import org.springframework.stereotype.Repository;import com.lgy.base.BaseDaoImpl;import com.lgy.model.Address;import com.lgy.model.Product;@Repositorypublic class ProductDaoImpl extends BaseDaoImpl<Product> implements IProductDao {}package com.lgy.dao;import com.lgy.base.IBaseDao;import com.lgy.model.Part;public interface IPartDao extends IBaseDao<Part> {}package com.lgy.dao;import org.springframework.stereotype.Repository;import com.lgy.base.BaseDaoImpl;import com.lgy.model.Part;@Repositorypublic class PartDaoImpl extends BaseDaoImpl<Part> implements IPartDao {}


测试代码如下:

@Testpublic void insert2Test() {Product product = new Product();List<String> parts = new ArrayList<String>();product.setName("麦克维");for (int i = 0; i < 5 ; i++) {Part part = new Part();part.setName("haha" + i);part.setCost(45D+ i);partDao.save(part);parts.add(part.getId());}product.setParts(parts);productDao.save(product);}
优势:部件作为独立文档存在,可以对某一部件进行独立的操作,比如查看和跟新。
缺点:必须通过2次查询才能找到某个产品的部件信息。




c.n代表很多个部分的时候

        比如,每一个机器(host)会产生很大数量的日志信息(logmsg)。在这种情况下,如果你采用嵌入式建模,则一个host文档会非常庞大,从而轻易超过MongoDB的文档大小限制,所以不可行。如果你采用第二中方式建模,用数组来存放所有logmsg的_id值,这种方式同样不可行,因为当日止很多时,即使单单引用objectId也会轻易超过文档大小限制。所以此时,我们采用以下方式,数据格式如下:

/* 0 */{  "_id" : ObjectId("55dabfcae81f0c2821d2ccb6"),  "_class" : "com.lgy.model.Host",  "name" : "feng",  "ip" : "192.168.6.69"}-------------------------------------------------/* 0 */{  "_id" : ObjectId("55dabfcae81f0c2821d2ccb7"),  "_class" : "com.lgy.model.Log",  "msg" : "这个IP有异常",  "hostId" : "55dabfcae81f0c2821d2ccb6"}/* 1 */{  "_id" : ObjectId("55dabfcae81f0c2821d2ccb8"),  "_class" : "com.lgy.model.Log",  "msg" : "这个IP挂了",  "hostId" : "55dabfcae81f0c2821d2ccb6"}


java代码实现方式如下:

model层代码:

        

package com.lgy.model;import java.io.Serializable;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.Document;@Document(collection="host")public class Host implements Serializable {private static final long serialVersionUID = 4858632495675595186L;@Idprivate String id;private String name;private String ip;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}}package com.lgy.model;import java.io.Serializable;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.Document;@Document(collection="log")public class Log implements Serializable {private static final long serialVersionUID = -3445931472378980445L;@Idprivate String id;private String msg;private String hostId;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getHostId() {return hostId;}public void setHostId(String hostId) {this.hostId = hostId;}}


dao层代码:

package com.lgy.dao;import com.lgy.base.IBaseDao;import com.lgy.model.Host;public interface IHostDao extends IBaseDao<Host> {}package com.lgy.dao;import org.springframework.stereotype.Repository;import com.lgy.base.BaseDaoImpl;import com.lgy.model.Host;@Repositorypublic class HostDaoImpl extends BaseDaoImpl<Host> implements IHostDao {}package com.lgy.dao;import com.lgy.base.IBaseDao;import com.lgy.model.Log;public interface ILogDao extends IBaseDao<Log> {}package com.lgy.dao;import org.springframework.stereotype.Repository;import com.lgy.base.BaseDaoImpl;import com.lgy.model.Log;@Repositorypublic class LogDaoImpl extends BaseDaoImpl<Log> implements ILogDao {}


测试代码如下:

@Testpublic void insert3Test() {Host host = new Host();host.setName("feng");host.setIp("192.168.6.69");hostDao.save(host);Log log1 = new Log();log1.setHostId(host.getId());log1.setMsg("这个IP有异常");logDao.save(log1);Log log2 = new Log();log2.setHostId(host.getId());log2.setMsg("这个IP挂了");logDao.save(log2);}
          我们在log中,存放对host的_id引用即可。
 



在1对n的关系中,总结如下:
    (1)在数据量很少的情况下,采用嵌入式文档方式来进行建立关联关系;
    (2)在数据量比较多的情况下,采用引用方式来建模,在1的那一方,引用多个文档的id
    (3)在数据量特别多的情况下,采用引用方式来建模,在多的那一方,引用关联的文档id




*封装的IBaseDao和BaseDaoIpml代码如下:

package com.lgy.base;import java.util.List;import org.springframework.data.mongodb.core.query.Query;import org.springframework.data.mongodb.core.query.Update;public interface IBaseDao<T> {public void save(T t) ; public T findOneById(Object id);public List<T> findAll();public void deleteByModel(T t);public void deleteByQuery(Query query);public void update(Query query, Update update);}package com.lgy.base;import java.lang.reflect.ParameterizedType;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.query.Query;import org.springframework.data.mongodb.core.query.Update;public class BaseDaoImpl<T> implements IBaseDao<T> {@Autowired    protected MongoTemplate mongoTemplate;protected Class<T> clazz;@SuppressWarnings("unchecked")public BaseDaoImpl() { ParameterizedType pt = (ParameterizedType) this.getClass()                .getGenericSuperclass();     this.clazz = (Class<T>) pt.getActualTypeArguments()[0];}public void save(T t) {this.mongoTemplate.save(t);}public T findOneById(Object id) {return this.mongoTemplate.findById(id, clazz);}public List<T> findAll() {return this.mongoTemplate.findAll(clazz);}public void deleteByModel(T t) {this.mongoTemplate.remove(t);}public void deleteByQuery(Query query) {this.mongoTemplate.remove(query, clazz);}public void update(Query query, Update update) {this.mongoTemplate.upsert(query, update, clazz);}}





0 0
原创粉丝点击