【问题标题】:MongoDb upsert exception invalid BSON fieldMongoDb upsert 异常无效的 BSON 字段
【发布时间】:2017-09-28 10:22:39
【问题描述】:

这个例外:

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 ); 执行良好。

为什么插入没问题,而“upsert”却不行?

【问题讨论】:

    标签: java mongodb upsert


    【解决方案1】:

    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/

    【讨论】:

      【解决方案2】:

      另一个选项是setOnInsert,如MongoDB的文档所示:

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

      该操作仅在upserttrue 时有效。

      在您的情况下,您应该将不修改的字段放在一个文档中,将要更新的字段放在另一个文档中,并在第三个文档中分别添加 $setOnInsert$set 作为键。

      $setOnInsert的一大优点是插入时会执行$setOnInsert$set部分,但更新时只会执行$set

      例如,我们有一个要插入/更新的文档,它有 5 个字段:nameagegendercreateAtupdateAt

      • 当我通过字段“名称”进行查询并找不到匹配项时,我想插入包含 5 个字段的文档,并用当前日期时间填充 createAtupdateAt
      • 当我通过“名称”进行查询并找到匹配项时,我想用当前日期时间更新 nameupdateAt

      我做的是:

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

      【讨论】:

        猜你喜欢
        • 2021-01-13
        • 2021-12-31
        • 2021-04-17
        • 1970-01-01
        • 2017-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-22
        相关资源
        最近更新 更多