基本上,我有一个
User
集合,其中包含@DbRef 到UserPlot
(图)集合。在UserPlot
里面,我还有一个@DbRef到Plot
(情节)。我的目标是找到所有用户并急切地将图加载到User
(也急切地将图加载到UserPlot)
@Data
@NoArgsConstructor
@Document(collection = "users")
public class User {
@Id private String id;
@Indexed(name = "ui_email", unique = true)
private String email;
private String password;
@Indexed(name = "ui_first_name")
private String firstName;
@Indexed(name = "ui_last_name")
private String lastName;
@DBRef
private List<UserPlot> plots;
}
@Data
@Document(collection = "users_have_plots")
public class UserPlot {
@Id
private String id;
private String userId;
@DBRef
private Plot plot;
}
@Data
@Document(collection = "plots")
@NoArgsConstructor
public class Plot {
@Id
private String id;
private Integer x;
private Integer y;
}
@Repository
public interface UserRepository extends ReactiveMongoRepository<User, String> {
@Aggregation(pipeline = {
// Join user and user_plot collections on user id
"{$lookup: {from: 'users_have_plots', localField: '_id', foreignField: 'userId', as: 'plots'}}",
// Unwind plots array to get individual user_plot documents
"{$unwind: {path: '$plots', preserveNullAndEmptyArrays: true}}",
// Join plots collection on user_plot's plot id
"{$lookup: {from: 'plots', localField: 'plots.plot', foreignField: '_id', as: 'plots.plot'}}",
// Group user and user_plot documents back into a single document
"{$group: {_id: '$_id', email: {$first: '$email'}, password: {$first: '$password'}, firstName: {$first: '$firstName'}, lastName: {$first: '$lastName'}, plots: {$push: '$plots'}}}"
})
Flux<User> findAllIncludePlots();
}
@SpringBootApplication(exclude = UserDetailsServiceAutoConfiguration.class)
@EnableReactiveMongoRepositories
public class FarmApplication {
public static void main(String[] args) {
SpringApplication.run(FarmApplication.class, args);
}
@Bean
CommandLineRunner t(PlotRepository plotRepository, UserPlotRepository userPlotRepository, UserRepository userRepository) {
return a -> {
plotRepository.save(new Plot(0, 0)).zipWith(userRepository.findAll().next()).map(t -> {
Plot t1 = t.getT1();
User t2 = t.getT2();
UserPlot up = new UserPlot();
up.setPlot(t1);
up.setUserId(t2.getId());
return userPlotRepository.save(up)
.map(e -> {
t2.getPlots().add(e);
return t2;
})
.flatMap(userRepository::save);
}).flatMap(Function.identity()).subscribe(System.out::println, System.err::println);
//this line throws error
userRepository.findAllIncludePlots().map(User::getPlots).doOnNext(System.out::println).subscribe();
};
}
}
当我调用
userRepository.findAllIncludePlots().map(User::getPlots).doOnNext(System.out::println).subscribe();
然后我得到这个错误:
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 15983 (Location15983): 'An object representing an expression must have exactly one field: { $ref: "users_have_plots", $id: "$plots" }' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "An object representing an expression must have exactly one field: { $ref: \"users_have_plots\", $id: \"$plots\" }", "code": 15983, "codeName": "Location15983"}
Caused by: org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 15983 (Location15983): 'An object representing an expression must have exactly one field: { $ref: "users_have_plots", $id: "$plots" }' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "An object representing an expression must have exactly one field: { $ref: \"users_have_plots\", $id: \"$plots\" }", "code": 15983, "codeName": "Location15983"}
at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:136) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.potentiallyConvertRuntimeException(ReactiveMongoTemplate.java:2574) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.lambda$translateException$93(ReactiveMongoTemplate.java:2557) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
at reactor.core.publisher.Flux.lambda$onErrorMap$27(Flux.java:7088) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onError(MonoFlatMapMany.java:255) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.maybeOnError(FluxConcatMapNoPrefetch.java:326) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onError(FluxConcatMapNoPrefetch.java:220) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$BaseSink.error(FluxCreate.java:474) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:802) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$BufferAsyncSink.error(FluxCreate.java:747) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$SerializedFluxSink.drainLoop(FluxCreate.java:237) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$SerializedFluxSink.drain(FluxCreate.java:213) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxCreate$SerializedFluxSink.error(FluxCreate.java:189) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.LambdaMonoSubscriber.doError(LambdaMonoSubscriber.java:155) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.LambdaMonoSubscriber.onError(LambdaMonoSubscriber.java:150) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoNext$NextSubscriber.onError(MonoNext.java:93) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoNext$NextSubscriber.onError(MonoNext.java:93) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:241) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:315) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:258) ~[reactor-core-3.5.0.jar:3.5.0]
at reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:201) ~[reactor-core-3.5.0.jar:3.5.0]
at com.mongodb.reactivestreams.client.internal.MongoOperationPublisher.lambda$sinkToCallback$31(MongoOperationPublisher.java:573) ~[mongodb-driver-reactivestreams-4.8.0.jar:na]
at com.mongodb.reactivestreams.client.internal.OperationExecutorImpl.lambda$execute$2(OperationExecutorImpl.java:94) ~[mongodb-driver-reactivestreams-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.function.RetryingAsyncCallbackSupplier$RetryingCallback.onResult(RetryingAsyncCallbackSupplier.java:111) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.operation.CommandOperationHelper.lambda$transformingReadCallback$10(CommandOperationHelper.java:323) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor$1.onResult(DefaultServer.java:238) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.CommandProtocolImpl$1.onResult(CommandProtocolImpl.java:82) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection$1.onResult(DefaultConnectionPool.java:683) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.UsageTrackingInternalConnection$2.onResult(UsageTrackingInternalConnection.java:159) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:46) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:526) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:501) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:824) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:788) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:648) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:319) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:266) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:645) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection.access$600(InternalStreamConnection.java:89) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:778) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:763) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:648) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:319) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream.handleReadResponse(NettyStream.java:347) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream.access$1100(NettyStream.java:105) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:421) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:418) ~[mongodb-driver-core-4.8.0.jar:na]
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.85.Final.jar:4.1.85.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.85.Final.jar:4.1.85.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.85.Final.jar:4.1.85.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.85.Final.jar:4.1.85.Final]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Caused by: com.mongodb.MongoCommandException: Command failed with error 15983 (Location15983): 'An object representing an expression must have exactly one field: { $ref: "users_have_plots", $id: "$plots" }' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "An object representing an expression must have exactly one field: { $ref: \"users_have_plots\", $id: \"$plots\" }", "code": 15983, "codeName": "Location15983"}
at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:198) ~[mongodb-driver-core-4.8.0.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:515) ~[mongodb-driver-core-4.8.0.jar:na]
... 35 common frames omitted
我觉得我的
@Aggregation
有问题,但我找不到原因。请帮忙。谢谢
编辑:我的数据看起来像
vilya_be> db.plots.find({})
[
{
_id: ObjectId("6426b069ca83da130cdb7f70"),
x: 0,
y: 0,
_class: 'com.vilya.farm.domain.model.Plot'
}
]
vilya_be> db.users_have_plots.find({})
[
{
_id: ObjectId("6426b073ca83da130cdb7f71"),
userId: '6412c76956d4170a7de34d92',
plot: DBRef("plots", ObjectId("6426b069ca83da130cdb7f70")),
_class: 'com.vilya.farm.domain.model.UserPlot'
}
]
vilya_be> db.users.find({})
[
{
_id: ObjectId("6412c76956d4170a7de34d92"),
email: '[email protected]',
password: '$2a$10$s9VgOYd.fOKZF66TnAsjWemiCYkA7aG45NJpuSNgbVxpcIGF7fWqu',
firstName: 'f',
lastName: 'l',
plots: [ DBRef("users_have_plots", ObjectId("6426b073ca83da130cdb7f71")) ],
_class: 'com.vilya.farm.domain.model.User'
},
{
_id: ObjectId("6414667360e4ba4481052627"),
email: '[email protected]',
password: '$2a$10$OP52phZ61l2JX2e2TQOu9ubYFBYcPeqEZ92ox2Nyyp5e.MEZk7GhS',
firstName: 'f',
lastName: 'l',
_class: 'com.vilya.farm.domain.model.User'
}
]
mongo 版本:mongo:6.0.2-focal 运行在 docker desktop 上