2014-09-24 64 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