Java MongoDb upsert 异常无效的 BSON 字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43711716/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoDb upsert exception invalid BSON field
提问by Aubin
This exception:
这个例外:
Exception in thread "Thread-1" java.lang.IllegalArgumentException: Invalid BSON field name id
at org.bson.AbstractBsonWriter.writeName(AbstractBsonWriter.java:516)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:188)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:131)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
at com.mongodb.connection.UpdateCommandMessage.writeTheWrites(UpdateCommandMessage.java:85)
at com.mongodb.connection.UpdateCommandMessage.writeTheWrites(UpdateCommandMessage.java:43)
at com.mongodb.connection.BaseWriteCommandMessage.encodeMessageBodyWithMetadata(BaseWriteCommandMessage.java:129)
at com.mongodb.connection.RequestMessage.encodeWithMetadata(RequestMessage.java:160)
at com.mongodb.connection.WriteCommandProtocol.sendMessage(WriteCommandProtocol.java:220)
at com.mongodb.connection.WriteCommandProtocol.execute(WriteCommandProtocol.java:101)
at com.mongodb.connection.UpdateCommandProtocol.execute(UpdateCommandProtocol.java:64)
at com.mongodb.connection.UpdateCommandProtocol.execute(UpdateCommandProtocol.java:37)
at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:168)
at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:289)
at com.mongodb.connection.DefaultServerConnection.updateCommand(DefaultServerConnection.java:143)
at com.mongodb.operation.MixedBulkWriteOperation$Run.executeWriteCommandProtocol(MixedBulkWriteOperation.java:490)
at com.mongodb.operation.MixedBulkWriteOperation$Run$RunExecutor.execute(MixedBulkWriteOperation.java:656)
at com.mongodb.operation.MixedBulkWriteOperation$Run.execute(MixedBulkWriteOperation.java:409)
at com.mongodb.operation.MixedBulkWriteOperation.call(MixedBulkWriteOperation.java:177)
at com.mongodb.operation.MixedBulkWriteOperation.call(MixedBulkWriteOperation.java:168)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:413)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:168)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:74)
at com.mongodb.Mongo.execute(Mongo.java:845)
at com.mongodb.Mongo.execute(Mongo.java:828)
at com.mongodb.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:550)
at com.mongodb.MongoCollectionImpl.update(MongoCollectionImpl.java:542)
at com.mongodb.MongoCollectionImpl.updateOne(MongoCollectionImpl.java:381)
at org.hpms.gis.MongoDbTest.insert(MongoDbTest.java:63)
at java.lang.Thread.run(Thread.java:748)
is thrown by the following code:
由以下代码抛出:
final UUID id = UUID.randomUUID();
final double frequency = 8_000.0 + ( 10_000.0 * Math.random() );
final double startSec = 100*i;
final double startNano = 10*i;
final double endSec = startSec + ( 100*i );
final double endNano = startNano + ( 10*i );
final double latitude = ( 180.0*Math.random() ) - 90.0;
final double longitude = ( 360.0*Math.random() ) - 180.0;
final Document trackID = new Document(
"id", new Document(
"msb", id.getMostSignificantBits ()) .append(
"lsb", id.getLeastSignificantBits()));
final Document track = new Document(
"id", new Document(
"msb", id.getMostSignificantBits ()) .append(
"lsb", id.getLeastSignificantBits())).append(
"frequency", frequency ) .append(
"start", new Document(
"seconds", startSec ) .append(
"nanoSec", startNano )).append(
"end", new Document(
"seconds", endSec ) .append(
"nanoSec", endNano )).append(
"position", new Document(
"latitude" , latitude ) .append(
"longitude", longitude )).append(
"padding", new byte[1000-8-8-8-4-4-4-4-8-8] );
//_collection.insertOne( track );
_collection.updateOne(
trackID,
track,
new UpdateOptions().upsert( true ));
The commented code _collection.insertOne( track );executes fine.
注释的代码_collection.insertOne( track );执行良好。
Why the insert is fine when the "upsert" is not?
为什么当“upsert”不是时插入是好的?
采纳答案by Sagar Veeram
updateOnefor updating document fields using update operators. You need replaceOnewhich takes the replacement document.
updateOne用于使用更新运算符更新文档字段。您需要replaceOne哪个取替换文件。
_collection.replaceOne(
trackID,
track,
new UpdateOptions().upsert( true ));
More here
更多在这里
Update Operators: https://docs.mongodb.com/manual/reference/operator/update-field/
更新操作员:https: //docs.mongodb.com/manual/reference/operator/update-field/
Update One:https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/
更新一:https: //docs.mongodb.com/manual/reference/method/db.collection.updateOne/
Replace One: https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
替换一:https: //docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
回答by WesternGun
Another option is setOnInsert, as shown in the document of MongoDB:
另一种选择是setOnInsert,如MongoDB的文档所示:
https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/
https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/
The operation works only when upsertis true.
操作只有当作品upsert是true。
In your case, you should put fields not to be modified in a document, and fields to be updated in another document, and in the third document, prepend $setOnInsertand $setas key, respectively.
在您的情况下,您应该将不要修改的字段放在一个文档中,将要更新的字段放在另一个文档中,并在第三个文档中分别放在前面$setOnInsert和$set作为键。
A big advantage of $setOnInsertis that when inserting, it will perform $setOnInsertand$setpart, but when updating, only $setwill be executed.
一个很大的优点$setOnInsert是插入时会执行$setOnInsert和$set部分,但更新时只会$set执行。
For example, we have a document to insert/update, which has 5 fields: name, age, gender, createAt, updateAt.
例如,我们有一个要插入/更新的文档,它有 5 个字段:name, age, gender, createAt, updateAt。
- When I do a query by field "name" and find no match, I want to insert the document with 5 fields, and fill
createAtandupdateAtwith current datetime. - When I do a query by "name" and find a match, I want to update
nameandupdateAtwith current datetime.
- 当我按字段“名称”进行查询并没有找到匹配项时,我想插入具有 5 个字段的文档,
createAt并updateAt使用当前日期时间填充和。 - 当我做的“名称”查询,并找到一个匹配,我想更新
name,并updateAt与当前日期时间。
What I do is:
我要做的是:
query = Filters.eq("name", nameToSearch);
Document upsert = new Document();
Date now = new Date();
//only fields not mentioned in "$set" is needed here
Document toInsert = new Document()
.append("age", newAge)
.append("gender", genderString)
.append("createAt", now);
//the fields to update here, whether on insert or on update.
Document toUpdate = new Document().append("name", nameToSearch)
.append("updateAt", now);
//will:
// - insert 5 fields if query returns no match
// - updates 2 fields if query returns match
upsert.append("$setOnInsert", toInsert)
.append("$set", toUpdate);
UpdateResult result = collection.updateOne(query, toUpdate,
new UpdateOptions().upsert(true));

