英文:
Unrecognized pipeline stage name: '$setOnInsert'
问题
在使用版本为 4.4.1 的独立 MongoDB 实例,使用最新驱动程序 (org.mongodb:mongodb-driver-sync:4.1.1
) 连接的 Java 客户端时,调用带有 $setOnInsert 运算符的 findOneAndUpdate
方法时出现错误。
以下是使用的查询:
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));
错误信息:
> Exception in thread "main" com.mongodb.MongoCommandException: Command
> failed with error 40324 (Location40324): 'Unrecognized pipeline stage
> name: '$setOnInsert'' on server A.B.C.D:XXXXX. The full
> response is {"ok": 0.0, "errmsg": "Unrecognized pipeline stage
> name: '$setOnInsert'", "code": 40324, "codeName": "Location40324"} at
> ...
如果去掉 Updates.setOnInsert(...)
调用,更新可以正常工作,但不符合我的期望。我的目的是根据要更新的文档是否存在来设置一些字段。根据文档,应该支持使用 $setOnInsert :
https://docs.mongodb.com/manual/reference/operator/update/#id1
对于这个问题有什么想法吗?
英文:
Using a standalone MongoDB instance in version 4.4.1 with a Java client that connects using the latest driver (org.mongodb:mongodb-driver-sync:4.1.1
), I am getting an error when calling findOneAndUpdate
with the $setOnInsert operator.
Here is the query used:
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));
The error:
> Exception in thread "main" com.mongodb.MongoCommandException: Command
> failed with error 40324 (Location40324): 'Unrecognized pipeline stage
> name: '$setOnInsert'' on server A.B.C.D:XXXXX. The full
> response is {"ok": 0.0, "errmsg": "Unrecognized pipeline stage name:
> '$setOnInsert'", "code": 40324, "codeName": "Location40324"} at
> com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175)
> at
> com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:359)
> at
> com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:280)
> at
> com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:100)
> at
> com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:490)
> at
> com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71)
> at
> com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:255)
> at
> com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:202)
> at
> com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:118)
> at
> com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:110)
> at
> com.mongodb.internal.operation.CommandOperationHelper$13.call(CommandOperationHelper.java:712)
> at
> com.mongodb.internal.operation.OperationHelper.withReleasableConnection(OperationHelper.java:620)
> at
> com.mongodb.internal.operation.CommandOperationHelper.executeRetryableCommand(CommandOperationHelper.java:705)
> at
> com.mongodb.internal.operation.CommandOperationHelper.executeRetryableCommand(CommandOperationHelper.java:697)
> at
> com.mongodb.internal.operation.BaseFindAndModifyOperation.execute(BaseFindAndModifyOperation.java:69)
> at
> com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:195)
> at
> com.mongodb.client.internal.MongoCollectionImpl.executeFindOneAndUpdate(MongoCollectionImpl.java:785)
> at
> com.mongodb.client.internal.MongoCollectionImpl.findOneAndUpdate(MongoCollectionImpl.java:765)
If I get rid of the Updates.setOnInsert(...)
call, then the update works but not as I would like. My purpose is to set some fields based on whether the document to update exists or not. Looking at the documentation, $setOnInsert should be supported:
https://docs.mongodb.com/manual/reference/operator/update/#id1
Any idea about what is wrong?
答案1
得分: 1
这里的问题是findOneAndUpdate
有两种形式。第二个参数可以是以下之一:
- 包含更新操作符表达式的文档
- 包含
$set
、$unset
和$replaceRoot
聚合阶段的数组
由于您将 updates
创建为一个 ArrayList,findOneAndUpdate
试图将其处理为聚合管道,但聚合管道不识别 $setOneInsert
阶段。
您需要将 updates
构建为一个 Document,以便识别更新操作符。按照您的示例,您可以简单地使用 Updates.combine(updates)
将列表包装起来,并将其作为第二个参数传递给 findOneAndUpdate
。
英文:
The problem here is there are 2 forms of findOneAndUpdate. The second argument can be either:
- a document containing update operator expressions
- an array containing
$set
,$unset
, and$replaceRoot
aggregation stages
Since you are creating updates
as an ArrayList, findOneAndUpdate is trying to process it as an aggregation pipeline, which does not recognize a $setOneInsert
stage.
You need to build updates
as a Document for the update operators to be recognized. Following your example, you can simply wrap the list with Updates.combine(updates)
and pass it to findOneAndUpdate
as the second parameter.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论