我正在使用java / morphia来处理mongodb。从Java层使用默认的ObjectId不是很方便。我想在使用ObjectId保持密钥生成过程时使其成为String类型,比如_id = new ObjectId.toString()
。
我想知道这样做是否有任何副作用?例如,它是否会影响数据库性能或以任何方式导致密钥冲突?它会影响分片环境......
答案 0 :(得分:19)
您可以为_id
字段使用任何类型的值(数组除外)。如果您选择不使用ObjectId,则必须以某种方式保证值的唯一性(将ObjectId强制转换为字符串)。如果您尝试插入重复键,则会发生错误,您将不得不处理它。
当您尝试将具有相同_id的两个文档插入到不同的分片时,我不确定它对分片群集有什么影响。我怀疑它会让你插入,但这会在以后咬你。 (我必须测试一下)。
那就是说_id = (new ObjectId).toString()
你应该没有麻烦。
答案 1 :(得分:5)
我实际上做了同样的事情,因为我在将ObjectId转换为JSON时遇到了一些问题。
然后我做了类似
的事情@Id
private String id;
public String getId() {
return id();
}
public void setId(String id) {
this.id = id;
}
一切正常,直到我决定更新以前插入的文档,当我通过Id将对象通过JSON发送到页面并通过JSON post接收相同的更新对象然后使用数据存储区中的save函数时,而不是更新以前的数据,它插入一个新文件,而不是更新已经存在的文件。
即使最糟糕的是,新文档的ID与之前插入的ID相同,我认为这是不可能的。
无论如何,我将私有对象设置为ObjectID,然后将get set保留为字符串,然后按预期工作,不确定在您的情况下是否有帮助。
@Id
private ObjectId id;
public String getId() {
return id.toString();
}
public void setId(String id) {
this.id = new ObjectId(id);
}
答案 2 :(得分:1)
是的,您可以使用字符串作为_id。
我建议只有你有一些价值(在文件中)自然是一个很好的唯一键。我在一个集合中使用了这个设计,其中有一个字符串geo-tag,形式为“xxxxyyyy”;这个每个文档的唯一字段必须在文档中和我必须在它上面构建一个索引...那么为什么不把它用作键? (这避免了一个额外的键值对,并且避免了集合上的第二个索引,因为MondoDB自然地在“_id”上建立索引。考虑到集合的大小,这两者都增加了一些严重的空间节省。)< / p>
但是,根据你的问题的语气(“ObjectIDs不是很方便”),如果你想要使用字符串的唯一原因是你不想被弄清楚如何整齐地管理ObjectIDs。我建议值得你花时间去理解他们。我确定他们没有麻烦......一旦你弄清楚他们的麻烦。
否则:你有什么选择?你是否会在将来使用MongoDB时编写字符串ID?
答案 3 :(得分:1)
我想补充一点,如果将自动生成的BSON ObjectID作为唯一标识符传递给应用程序并不总是一个好主意:它可能会被用户操纵。 ObjectID似乎是按顺序生成的,因此如果您未能实现必要的授权机制,恶意用户可以简单地增加他拥有的值,以访问他本不应该访问的资源。
因此,使用UUID类型标识符将提供一层透明的安全性。当然,授权(此用户是否允许访问所请求的资源)是必须的,但您应该了解上述ObjectID功能。
为了充分利用这两个世界,请生成与您的ObjectID长度(12或24个字符)匹配的UUID,并使用它来创建您自己的ObjectID类型的_id。
答案 4 :(得分:0)
您也可以使用字符串作为Java的ID。这是一个示例方法和相应的单元测试,在MongoDB集合中插入一个带有字符串ID的对象:
public Document insert(String json, String collectionName) {
MongoCollection<Document> collection = database.getCollection(collectionName);
BasicDBObject document = BasicDBObject.parse(json);
Document doc = new Document(document);
collection.insertOne(doc);
return doc;
}
@Test
void whenInsert_ShouldInsertOne() {
final String uuid = UUID.randomUUID().toString();
final String collection = "test_collection";
final Document doc = app.insert(String.format("{\"_id\":\"%s\", \"name\": \"test\"}",
uuid), collection);
assertThat(doc).isNotNull();
final String json = app.getById(uuid, collection);
assertThat(json).contains(String.format("\"_id\": \"%s\"", uuid));
}