无法识别的管道阶段名称:'$ setOnInsert'

时间:2020-10-27 17:55:40

标签: java mongodb mongodb-query

使用版本为 4.4.1 的独立MongoDB实例以及使用最新驱动程序(org.mongodb:mongodb-driver-sync:4.1.1)连接的Java客户端,我在调用findOneAndUpdate时遇到错误使用 $ setOnInsert 运算符。

以下是使用的查询:

final List<Bson> updates = new ArrayList<>();
updates.add(Updates.set("data", "test"));
updates.add(Updates.setOnInsert("firstSeenTime", new Date()));

final Document updatedDocument =
    this.visitorsCollection.findOneAndUpdate(
        eq("userId", "u1"), updates, new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER).upsert(true));

错误:

线程“ main”中的异常com.mongodb.MongoCommandException:命令 失败,错误40324(Location40324):“无法识别的管道阶段 服务器A.B.C.D:XXXXX上的名称:'$ setOnInsert'。完整的 响应为{“ ok”:0.0,“ errmsg”:“无法识别的管道阶段名称: '$ setOnInsert'“,”代码“:40324,” codeName“:” Location40324“}在 com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175) 在 com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:359) 在 com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:280) 在 com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:100) 在 com.mongodb.internal.connection.DefaultConnectionPool $ PooledConnection.sendAndReceive(DefaultConnectionPool.java:490) 在 com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71) 在 com.mongodb.internal.connection.DefaultServer $ DefaultServerProtocolExecutor.execute(DefaultServer.java:255) 在 com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:202) 在 com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:118) 在 com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:110) 在 com.mongodb.internal.operation.CommandOperationHelper $ 13.call(CommandOperationHelper.java:712) 在 com.mongodb.internal.operation.OperationHelper.withReleasableConnection(OperationHelper.java:620) 在 com.mongodb.internal.operation.CommandOperationHelper.executeRetryableCommand(CommandOperationHelper.java:705) 在 com.mongodb.internal.operation.CommandOperationHelper.executeRetryableCommand(CommandOperationHelper.java:697) 在 com.mongodb.internal.operation.BaseFindAndModifyOperation.execute(BaseFindAndModifyOperation.java:69) 在 com.mongodb.client.internal.MongoClientDelegate $ DelegateOperationExecutor.execute(MongoClientDelegate.java:195) 在 com.mongodb.client.internal.MongoCollectionImpl.executeFindOneAndUpdate(MongoCollectionImpl.java:785) 在 com.mongodb.client.internal.MongoCollectionImpl.findOneAndUpdate(MongoCollectionImpl.java:765)

如果我摆脱了Updates.setOnInsert(...)的电话,那么更新就可以了,但是不如我所愿。我的目的是根据是否存在要更新的文档来设置一些字段。查看文档,应该支持 $ setOnInsert

https://docs.mongodb.com/manual/reference/operator/update/#id1

有什么不好的主意吗?

1 个答案:

答案 0 :(得分:1)

这里的问题是findOneAndUpdate有2种形式。第二个参数可以是:

  • 包含更新运算符表达式的文档
  • 包含$set$unset$replaceRoot聚合阶段的数组

由于您将updates创建为ArrayList,因此findOneAndUpdate尝试将其作为聚合管道处理,无法识别$setOneInsert阶段。

您需要将updates构建为文档,以便识别更新操作符。按照您的示例,您可以简单地用Updates.combine(updates)包装列表,并将其作为第二个参数传递给findOneAndUpdate