[JAVA-3872] Unrecognized pipeline stage name: '$setOnInsert' Created: 27/Oct/20  Updated: 27/Oct/23  Resolved: 27/Oct/20

Status: Closed
Project: Java Driver
Component/s: None
Affects Version/s: 4.1.1
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Laurent Pellegrino Assignee: Unassigned
Resolution: Works as Designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Standalone MongoDB instance in version 4.4.1.

The App that runs the Mongo client is using Java 15.



 Description   

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

Unknown macro: {"ok"}

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

I am wondering if I misuse the API or if that's a bug.



 Comments   
Comment by Jeffrey Yemin [ 27/Oct/20 ]

Hi laurent.pellegrino@gmail.com

Indeed, you're misusing the API, though I see now that it's quite easy to do.

There are two main overloads of the findOneAndUpdate method. One that takes a normal update document, and one that takes an aggregation pipeline. You're using the latter when you need to use the former. Try this instead:

        Bson updates = Updates.combine(
                Updates.set("data", "test"),
                Updates.setOnInsert("firstSeenTime", new Date()));
        Document updatedDocument =
                visitorsCollection.findOneAndUpdate(
                        eq("userId", "u1"), updates,
                        new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER).upsert(true));

Update.combine is unfortunately a bit buried in the reference documentation.

Generated at Thu Feb 08 09:00:39 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.