MongoDB:如果记录不存在,则插入记录,如果存在则忽略。

7
我有一系列类似于MongoDB记录的数据:
{"name":"Bob", "gpa":4} {"name":"Sarah", "gpa":3}
我将会遇到各种可能与同一人有关,也可能不相关的记录。如果它们是新的人,我想接受它们,如果它们是我们之前见过的人,我就不想更新它们。因此,如果我得到 {"name":"Jim", "gpa":2},我希望按原样接受它。如果我得到 {"name":"Sarah", "gpa":4}(不同的GPA值),我只想忽略它。这似乎既不是使用“upsert”设置为是的“update”的逻辑,也不是使用“upsert” 的“findAndModify”的逻辑。 https://dev59.com/FHE85IYBdhLWcg3wYigB#3260290建议一种方法(在第一个字段上创建唯一索引,插入记录,立即更新第二个字段),但这是几年前的事了,我想知道现在是否有更好的方法可以在单个步骤中完成。
编辑:
接受的答案看起来很好,但对我没用!首先,我创建了索引(这是使用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 }

创建了第二条记录,得分仍然更高。字段的顺序是否重要?似乎不应该,我也不知道如何控制它。

修复您的ensureIndex调用,根据@tripvolpe下面的答案应该可以解决您的问题。如果确实解决了,请接受trip的答案。 - ericsoco
2个回答

7

实现这一目标的最佳方法是在名称字段上设置唯一索引,使用以下命令:

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

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

谢谢,我没有意识到你可以在单个字段上保证这一点。 - umbraphile
奇怪的是,这个不起作用。我在上面发布了一堆代码,希望有人能发现我的错误。 - umbraphile
我有同样的问题。我不认为你解决了它吧? - Johan

6
您的ensureIndex()调用并不完全正确。 ensureIndex()的第一个参数包含应该建立索引的键; 索引选项(例如唯一性)可以作为第二个参数传递。 请参见Java driver docs
您目前尝试在“name”和“unique”两个字段上创建非唯一索引。
尝试使用以下内容创建索引:
DBObject nameIndex = new BasicDBObject();
nameIndex.put("name",1);

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

queue.ensureIndex(nameIndex, nameIndexOptions);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接