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
updateOne
for updating document fields using update operators. You need replaceOne
which 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 upsert
is 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 $setOnInsert
and $set
as key, respectively.
在您的情况下,您应该将不要修改的字段放在一个文档中,将要更新的字段放在另一个文档中,并在第三个文档中分别放在前面$setOnInsert
和$set
作为键。
A big advantage of $setOnInsert
is that when inserting, it will perform $setOnInsert
and$set
part, but when updating, only $set
will 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
createAt
andupdateAt
with current datetime. - When I do a query by "name" and find a match, I want to update
name
andupdateAt
with 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));