2

不幸的是, Quarkus Guide on using MongoDB with Panache没有提到处理一对多实体关系的最佳实践。注意:我想对依赖的子文档进行建模,但要单独作为一个实体。MongoDB 站点在以下方面演示了这种模式:使用文档引用建模一对多关系,以便您必须在存储库中查找链接到父 ID 的所有实体。

Quarkus (Panache) 目前是否提供任何使查找更方便的方法?

PS:似乎从 2020 年 5 月开始有一个开放的增强请求来自动获取引用的实体。

4

2 回答 2

3

正如@loicmathieu 所告知的那样,在 quarkus 中没有直接的方法可以做populate(),因为你可以在 mongoose 中做。如果您设置mongoose.set('debug', true)了,那么您可以先在控制台中签入

  • find执行集合查询
  • in执行对参考集合的查询。

示例 json 文档:

{
    "_id" : ObjectId("612f6c5c081d0796761ec2e4"),
    "content" : "cannot restart Mongodb even when memory space is available",
    "created_by" : ObjectId("612cb8608d22afb0e404adf6"),
    "tags" : [ 
        ObjectId("612f6c5c081d0796761ec2e2")
    ],
    "createdAt" : ISODate("2021-09-01T12:04:44.361Z"),
    "updatedAt" : ISODate("2021-09-10T05:30:51.384Z"),
    "__v" : 2,
    "likes" : [],
    "replies" : []
}

标记文件

{
    "_id" : ObjectId("612f6c5c081d0796761ec2e2"),
    "name" : "mongodb",
    "created_by" : ObjectId("612cb8608d22afb0e404adf6"),
    "createdAt" : ISODate("2021-09-01T12:04:44.358Z"),
    "updatedAt" : ISODate("2021-09-01T12:04:44.358Z"),
    "__v" : 0
}

最后是用户文档

{
    "_id" : ObjectId("612cb8608d22afb0e404adf6"),
    "username" : "silentsudo",
    "password" : "sosimplebcrypted",
    "name" : "Ashish",
    "__v" : 0
}

要获取所有文档,我执行以下查询:

exports.getRecentTweets = async () => {
    return Tweet.find()
        .populate('created_by', '_id name username mediaId')
        .populate('tags', '_id name')
        .sort({'createdAt': -1});
}

Mongoose 在内部以以下方式执行此操作

Mongoose: tweets.find({}, { sort: { createdAt: -1 }, projection: {} })
Mongoose: users.find({ _id: { '$in': [ new ObjectId("612cb8608d22afb0e404adf6"), new ObjectId("612f57ca9ea5c5cabbd89b38"), new ObjectId("612f57ae9ea5c5cabbd89b32"), new ObjectId("6134cb55328b793a1dacb9c2"), new ObjectId("612cb86a8d22afb0e404adfc") ] }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: { _id: 1, name: 1, username: 1, mediaId: 1 }})
Mongoose: tags.find({ _id: { '$in': [ new ObjectId("6144d9ef02f6da33f39fe134"), new ObjectId("612f6c5c081d0796761ec2e2"), new ObjectId("612f6e9f081d0796761ec343"), new ObjectId("612dc4623c401072c8098a84"), new ObjectId("612f6cb1081d0796761ec2f1"), new ObjectId("612f6c72081d0796761ec2eb"), new ObjectId("612f6e5b081d0796761ec337"), new ObjectId("612f6e42081d0796761ec330"), new ObjectId("612f6df9081d0796761ec320"), new ObjectId("612f6e0a081d0796761ec328"), new ObjectId("612f6de8081d0796761ec316"), new ObjectId("612f6de8081d0796761ec319"), new ObjectId("612f6dc9081d0796761ec30c"), new ObjectId("612f6dc9081d0796761ec30f"), new ObjectId("612f6db0081d0796761ec303"), new ObjectId("612f6db0081d0796761ec306"), new ObjectId("612f6cc7081d0796761ec2f7") ] }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: { _id: 1, name: 1 }})

我正在尝试ab tool进行基准测试。所以我决定使用 quarkus,因为我以前从未使用它构建过任何生产应用程序。所以我很快创建了模型并到达了这个线程,只是知道没有直接的方法可以在基于 java 的驱动程序中实现填充。但是我们可以使用$lookup 我们需要的聚合管道。第一种也是最简单的方法是使用 mongodb compass 工具构建查询,然后简单地将结果导出为 java 语言。我的 json 查询产生类似于填充查询的输出,如下所示。

[
  {
    '$unwind': {
      'path': '$tags', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$lookup': {
      'from': 'tags', 
      'localField': 'tags', 
      'foreignField': '_id', 
      'as': 'tweet_tags'
    }
  }, {
    '$unwind': {
      'path': '$tweet_tags', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$group': {
      '_id': '$_id', 
      'content': {
        '$first': '$content'
      }, 
      'user': {
        '$first': '$created_by'
      }, 
      'tags': {
        '$push': '$tweet_tags'
      }
    }
  }, {
    '$lookup': {
      'from': 'users', 
      'localField': 'user', 
      'foreignField': '_id', 
      'as': 'createdByUser'
    }
  }, {
    '$unwind': {
      'path': '$createdByUser', 
      'preserveNullAndEmptyArrays': false
    }
  }, {
    '$set': {
      'createdByUser.password': null
    }
  }
]

当转换成等效的java时给出

public static List<Document> getTweetByUserQuery() {
            return Arrays.asList(new Document("$unwind",
                            new Document("path", "$tags")
                                    .append("preserveNullAndEmptyArrays", true)),
                    new Document("$lookup",
                            new Document("from", "tags")
                                    .append("localField", "tags")
                                    .append("foreignField", "_id")
                                    .append("as", "tweet_tags")),
                    new Document("$unwind",
                            new Document("path", "$tweet_tags")
                                    .append("preserveNullAndEmptyArrays", true)),
                    new Document("$group",
                            new Document("_id", "$_id")
                                    .append("content",
                                            new Document("$first", "$content"))
                                    .append("user",
                                            new Document("$first", "$created_by"))
                                    .append("tags",
                                            new Document("$push", "$tweet_tags"))),
                    new Document("$lookup",
                            new Document("from", "users")
                                    .append("localField", "user")
                                    .append("foreignField", "_id")
                                    .append("as", "createdByUser")),
                    new Document("$unwind",
                            new Document("path", "$createdByUser")
                                    .append("preserveNullAndEmptyArrays", false)),
                    new Document("$set",
                            new Document("createdByUser.password",
                                    new BsonNull())));
        }

quarkus 控制器代码如下:

@Path("/hello")
public class ExampleResource {
    @Inject
    private MongoClient mongoClient;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Map<Object, Object> hello() {
        MongoCollection<Tweet> tweetsCollection = mongoClient.getDatabase("simple-node-js")
                .getCollection("tweets", Tweet.class);


        List<Document> groupByQueryUser = Tweet.GroupByIdDetails.getTweetByUserQuery();

        MongoCollection<Document> collections = mongoClient.getDatabase("simple-node-js")
                .getCollection("tweets");
        AggregateIterable<Document> aggregate = collections.aggregate(groupByQueryUser);
        List<Document> data = new ArrayList<>();
        for (Document value : aggregate) {
            System.out.println(value);
            data.add(value);
        }

        return Map.of("size", data.size(), "data", data);
    }


}

响应还需要做很多其他的事情,比如删除不需要的字段,但是这样我可以在 node+mongoose api 上获得相同的结果(除了我在这里跳过的一些事情)

于 2021-09-27T12:23:08.530 回答
0

MongoDB 是一个非关系型数据库,这就是为什么它没有一对多关系支持的原因。

我想对依赖的子文档进行建模,

我没有关注,支持子文档,您可以创建一个单独的 POJO 并将其用作您实体的属性。

不支持的是自动将引用的实体从一个集合加载到另一个集合,正如您指出的那样,有一个开放的增强请求支持它,您可以对其提供反馈(或通过 +1 投票)。

目前,对于引用的实体,您需要创建两个实体/存储库并手动进行 fecth。

于 2021-02-23T08:09:06.707 回答