2017-04-30 9 views
4

이 예외 :MongoDB를의 upsert 예외 무효 BSON 필드

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$3.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$1.call(MixedBulkWriteOperation.java:177) 
    at com.mongodb.operation.MixedBulkWriteOperation$1.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$2.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) 

은 다음 코드에 의해 발생합니다 :

 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)); 

주석으로 코드 _collection.insertOne(track); 잘 실행됩니다.

"업서 트"가 올바르지 않은 이유는 무엇입니까?

답변

13

updateOne 업데이트 연산자를 사용하여 문서 필드를 업데이트하는 경우. 대체 문서를 취하는 replaceOne이 필요합니다.

_collection.replaceOne(
     trackID, 
     track, 
     new UpdateOptions().upsert(true)); 

여기에 더

업데이트 운영자 : https://docs.mongodb.com/manual/reference/operator/update-field/

업데이트 한 : https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/

교체 한 : https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/

0

MongoDB를의 문서에서와 같이 또 다른 옵션은, setOnInsert입니다 :

upserttrue 경우에만

https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/

작업 작동합니다. 귀하의 경우에는

, 당신은 문서에 수정되지 않는 필드 및 필드 다른 문서에 업데이트, 세 번째 문서에 각각 키와 $setOnInsert$set을 앞에 추가 할을 넣어해야합니다.

$setOnInsert의 큰 장점은 삽입 할 때, $setOnInsert$set 일부를 수행하는 것이 있지만 업데이트하는 경우에만 $set 실행한다. name, age, gender, createAt, updateAt :

예를 들어, 우리는 5 개 필드가/업데이 트를 삽입 할 수있는 문서가 있습니다. 내가 필드 "이름"으로 쿼리를 수행하고 일치를 찾을 수없는 경우

  • , 나는 5 개 필드 문서를 삽입하고 현재 날짜와 createAtupdateAt을 채우려.
  • "name"으로 쿼리를 실행하고 일치 항목을 찾을 때 nameupdateAt을 현재 datetime으로 업데이트하려고합니다.

내가 할 것은 :

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));