【问题标题】:MongoDB: insert record if it doesn't exist, ignore if it doesMongoDB:如果不存在则插入记录,如果存在则忽略
【发布时间】:2012-03-28 11:39:08
【问题描述】:

我有一系列 MongoDB 记录,例如:

{"name":"Bob", "gpa":4} {"name":"Sarah", "gpa":3}

我会遇到可能属于或不属于同一个人的各种附加记录。如果他们是新人,我想接受他们,如果他们是我们以前见过的人,我想更新他们。所以如果我得到{"name":"Jim", "gpa":2},我想按原样接受。如果我得到{"name":"Sarah", "gpa":4}(不同的 GPA 值),我想忽略它。这似乎不是 update 将“upsert”设置为 yes 或 findAndModify 设置为“upsert”的逻辑。

https://stackoverflow.com/a/3260290/514757 提出了一种方法(第一个字段上的唯一索引,插入记录,立即更新第二个字段)但它已经有几年历史了,我想知道现在是否没有更好的方法可以一次性完成一步。

编辑:

接受的答案似乎很棒,但它对我不起作用!首先,我创建了索引(这是使用 Java 驱动程序):

nameIndex.put("name", 1);
nameIndex.put("unique", true);
queue.ensureIndex(nameIndex);

我可以从命令行看到索引存在并且是唯一的。然后,插入一个项目:

DBObject person = new BasicDBObject();
person.put("name", "Bob");
person.put("score", 200000);
queue.insert(person);

稍后,得分最高的项目将其分数降低到零:

BasicDBObject reset = new BasicDBObject();
reset.put("$set", new BasicDBObject("score", 0));
DBObject dbObj = queue.findAndModify(null, new BasicDBObject("score", -1), reset);

所有这些都按预期工作!但是,稍后,可能会再次找到相同的名称,并带有新的分数。当最后一段代码运行时,会创建一个具有不同分数的新项目,这正是我不想要的:

BasicDBObject queueable = new BasicDBObject();
queueable.put("name", "Could be Bob again, could be someone new");
queueable.put("score", 1234);
queue.insert(queueable);

如果我搜索 Bob,我会找到:

{ "_id" : ObjectId("4f5e865ad6d09315326ea0f0"), "score" : 0, "name" : "Bob" }
{ "_id" : ObjectId("4f5e8691d6d09315326ea190"), "name" : "Bob", "score" : 886 }

已创建第二条记录,再次获得更高的分数。字段的顺序重要吗?它似乎不应该,我不知道如何控制它。

【问题讨论】:

  • 字段的顺序无关紧要。根据下面@tripvolpe 的答案修复您的 ensureIndex 调用应该可以解决您的问题。如果是,请接受旅行的回答。

标签: java mongodb upsert


【解决方案1】:

完成此操作的最佳方法是使用以下方法在名称字段上设置唯一索引:

db.foo.ensureIndex({name:1}, {unique:true});

这将导致 Sarah 在您进行插入调用时不会得到更新,因为它会找到另一条记录,其中已经为 name 字段设置了“Sarah”。

【讨论】:

  • 谢谢,我没有意识到你可以保证在单个字段上。
  • 奇怪的是,这不起作用。我在上面贴了一堆代码,希望有人能发现我的错误。
  • 我遇到了一些问题。我不认为你设法解决它?
【解决方案2】:

您的 ensureIndex() 调用不太正确。 ensureIndex() 的第一个参数包含应该被索引的键;索引选项(如唯一性)可以作为第二个参数传递。请参阅Java driver docs

您现在正在尝试在两个字段上创建非唯一索引:“名称”和“唯一”。

试试这个来创建你的索引:

DBObject nameIndex = new BasicDBObject();
nameIndex.put("name",1);

DBObject nameIndexOptions = new BasicDBObject();
nameIndexOptions.put("unique", true);

queue.ensureIndex(nameIndex, nameIndexOptions);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    • 2018-04-02
    • 1970-01-01
    • 2018-09-17
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多