简体   繁体   English

如何避免在插入MongoDB时出现重复项

[英]How to be avoid duplicates entries at insert to MongoDB

I just want to be shure when inputting new DBObject to DB that it is really unique and Collection doesn't contain key field duplicates . 我只是想在将新的DBObject输入数据库时​​确信它确实是唯一的,并且Collection不包含关键字段重复项。

Here is how it looks now: 这是现在的样子:

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 is custom annotation: KeyFeld是自定义注释:

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

    String id();

    String get();

    String statusProp() default "ALL";

But I'm not shure that this solution really prove this. 但是我不确定该解决方案是否能证明这一点。 I'm newly at Mongo. 我刚来蒙哥。

Any suggestions? 有什么建议么?

A uniqueness can be maintained in MonboDb using _id field. 可以使用_id字段在MonboDb中维护唯一性。 If we will not provide the value of this field, MongoDB automatically creates a unique id for that particuler collection. 如果我们不提供此字段的值,则MongoDB会自动为该微粒集合创建一个唯一的ID。

So, in your case just create a property called _id in java & assign your unique field value here. 因此,在您的情况下,只需在Java中创建一个名为_id的属性,然后在此处分配您唯一的字段值即可。 If duplicated, it will throw an exception. 如果重复,它将引发异常。

With Spring Data MongoDB (the question was tagged with spring-data , that's why I suggest it), all you need is that: 使用Spring Data 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

The crucial part that's most related to your original question is @Indexed as this will cause the required unique index created when you create the repository. 与原始问题最相关的关键部分是@Indexed因为这将导致在创建存储库时创建所需的唯一索引。

What you get beyond that is: 您所获得的是:

  • no need to manually implement any repository (deleted code does not contain bugs \\o/) 无需手动实现任何存储库(已删除的代码不包含错误\\ o /)
  • automatic object-to-document conversion 自动对象到文档的转换
  • automatic index creation 自动索引创建
  • powerful repository abstraction to easily query data by declaring query methods 强大的存储库抽象,可通过声明查询方法轻松查询数据

For more details, check out the reference documentation . 有关更多详细信息,请参阅参考文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM