2014-09-24 73 views
1

我只想在将新的DBObject输入到DB时确保它是真正唯一的,并且Collection不包含关键字段重复项。如何避免在插入到MongoDB时重复条目

这是现在的样子:

public abstract class AbstractMongoDAO<ID, MODEL> implements GenericDAO<ID, MODEL> { 

    protected Mongo client; 

    protected Class<MODEL> model; 

    protected DBCollection dbCollection; 

    /** 
    * Contains model data : unique key name and name of get method 
    */ 
    protected KeyField keyField; 

    @SuppressWarnings("unchecked") 
    protected AbstractMongoDAO() { 
     ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass(); 
     model = (Class<MODEL>) genericSuperclass.getActualTypeArguments()[1]; 
     getKeyField(); 
    } 

    public void connect() throws UnknownHostException { 
     client = new MongoClient(Config.getMongoHost(), Integer.parseInt(Config.getMongoPort())); 
     DB clientDB = client.getDB(Config.getMongoDb()); 
     clientDB.authenticate(Config.getMongoDbUser(), Config.getMongoDbPass().toCharArray()); 
     dbCollection = clientDB.getCollection(getCollectionName(model)); 
    } 

    public void disconnect() { 
     if (client != null) { 
      client.close(); 
     } 
    } 

    @Override 
    public void create(MODEL model) { 
     Object keyValue = get(model); 
     try { 
      ObjectMapper mapper = new ObjectMapper(); 
      String requestAsString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(model); 
      // check if not presented 
      BasicDBObject dbObject = new BasicDBObject((String) keyValue, requestAsString); 
      dbCollection.ensureIndex(dbObject, new BasicDBObject("unique", true)); 
      dbCollection.insert(new BasicDBObject((String) keyValue, requestAsString)); 
     } catch (Throwable e) { 
      throw new RuntimeException(String.format("Duplicate parameters '%s' : '%s'", keyField.id(), keyValue)); 
     } 
    } 

private Object get(MODEL model) { 
    Object result = null; 
    try { 
     Method m = this.model.getMethod(this.keyField.get()); 
     result = m.invoke(model); 
    } catch (Exception e) { 
     throw new RuntimeException(String.format("Couldn't find method by name '%s' at class '%s'", this.keyField.get(), this.model.getName())); 
    } 
    return result; 
} 

/** 
* Extract the name of collection that is specified at '@Entity' annotation. 
* 
* @param clazz is model class object. 
* @return the name of collection that is specified. 
*/ 
private String getCollectionName(Class<MODEL> clazz) { 
    Entity entity = clazz.getAnnotation(Entity.class); 
    String tableName = entity.value(); 
    if (tableName.equals(Mapper.IGNORED_FIELDNAME)) { 
     // think about usual logger 
     tableName = clazz.getName(); 
    } 
    return tableName; 
} 

private void getKeyField() { 
    for (Field field : this.model.getDeclaredFields()) { 
     if (field.isAnnotationPresent(KeyField.class)) { 
      keyField = field.getAnnotation(KeyField.class); 
      break; 
     } 
    } 
    if (keyField == null) { 
     throw new RuntimeException(String.format("Couldn't find key field at class : '%s'", model.getName())); 
    } 
} 

KeyFeld是自定义注解:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface KeyField { 

    String id(); 

    String get(); 

    String statusProp() default "ALL"; 

但我不舒尔这个解决方案确实证明了这一点。我是新来的Mongo。

有什么建议吗?

+0

你看过Spring Data MongoDB吗?询问是因为你用spring-data标记了问题,但最终结束了编码,图书馆为你提供了什么OOTB。 – 2014-09-25 16:48:42

+0

@OliverGierke好的一击。我纠正了问题。 – 2014-09-26 08:26:55

回答

3

MonboDb使用_id字段可以保持唯一性。如果我们不提供这个字段的值,MongoDB会自动为该参数集合创建一个唯一的ID。

因此,在你的情况下,只需在java中创建一个名为_id的属性&在此处指定您的唯一字段值。如果重复,则会抛出异常。

+0

您还可以创建其他唯一键约束:请参见[创建唯一索引](http://docs.mongodb.org/manual/tutorial/create-a-unique-index/) – wdberkeley 2014-09-24 18:38:46

1

使用Spring数据的MongoDB(问题被标记为spring-data,这就是为什么我建议它),你需要的是:

// Your types 

class YourType { 

    BigInteger id; 
    @Indexed(unique = true) String emailAddress; 
    … 
} 

interface YourTypeRepository extends CrudRepository<YourType, BigInteger> { } 

// Infrastructure setup, if you use Spring as container prefer @EnableMongoRepositories 

MongoOperations operations = new MongoTemplate(new MongoClient(), "myDatabase"); 
MongoRepositoryFactory factory = new MongoRepositoryFactory(operations); 
YourTypeRepository repository = factory.getRepository(YourTypeRepository.class); 

// Now use it… 

YourType first = …; // set email address 
YourType second = …; // set same email address 

repository.save(first); 
repository.save(second); // will throw an exception 

这是最相关的你原来的问题最关键的部分是@Indexed,因为这将导致在创建存储库时创建必需的唯一索引。

你得到的超越是:

  • 无需手动执行任何存储库(删除代码不包含错误\ O /)
  • 自动对象到文档转换
  • 自动索引创作
  • 强大储存库抽象,以容易地通过声明查询方法

对于米查询数据矿石详情,请查看reference documentation