【问题标题】:SpringData - MongoDB fetch objects by IDs in the given orderSpring Data - MongoDB 按给定顺序按 ID 获取对象
【发布时间】:2018-05-01 12:34:20
【问题描述】:

我有一个这样的用例。我的 Mongo DB 中有问题,并且有一个 CRUD 微服务。在那里,我公开了一个 API 方法,通过查询参数给出的 ID 列表来获取问题。为了简单起见,用户给/api/questions?id=2, id=7, id=4, id = 5

然后我需要以完全相同的顺序返回问题列表,就像这样

questions: [
    {
       id: 2,
       prompt: "prompt one",
       ...
    },
    {
        id: 7,
        prompt: "prompt two",
        ...
    },
    {
        id: 4,
        ...
    },
    {
        id: 5
        ...
    }
]

但请注意,这既不是 ASC 也不是 DESC,而是可以是任意顺序,例如 /api/questions?id=2, id=7, id=4, id=5

我使用org.springframework.data.mongodb.repository.MongoRepository 作为我的DAO 课程。目前,在通过基于 spring-data 的存储库获取数据后,我正在我的服务层内进行排序。该解决方案有效。但我更愿意在 DAO 存储库级别本身完成此排序,因为它成本更低,并且不会在服务层为我的业务逻辑增加不必要的复杂性。相反,我可以仅将责任委托给数据库,假设它更有能力通过更多优化来做这些事情。

Mongo 文档结构如下所示。

我可以使用弹簧数据来实现这一点吗? 如果是这样,如何完成那件事?

【问题讨论】:

  • questions 是您结构的数组字段吗?如果是,那么它是可能的,但你必须使用聚合,因为排序数组比排序任何其他不是数组的字段有点棘手。如果您可以提供数据结构的虚拟示例,我可以为您提供帮助。另外,您使用正确的查询来获取文档?
  • 我现在使用默认的this.questionRepository.findAll(ids);。我正在寻找一种浓缩的方式。我相信聚合会更冗长。不是这样吗?我在那个存储库中没有mongoTemplate。
  • 它更冗长,但如果你想对数组进行排序,没有办法绕过它。它仍然会比在你的代码中排序更快。但如果您的ids 不在数组中,您可以使用this.questionRepository.findAll(ids).sort({id: -1}); 或sort({id: 1});。正如我所说,如果您使用虚拟文档更新您的问题,那么我可以告诉您是只需要排序还是聚合。
  • 我已根据您的要求添加了文档结构。如果有一种简洁的方法,请告诉我。谢谢!
  • 你粘贴了一张图片。一个虚拟的json会很棒。但无论如何,现在至少很清楚您必须使用聚合,并且您必须 $unwind 您的数组才能订购它。你提到你这样搜索this.questionRepository.findAll(ids)ids是什么?因为我无法想象"options.id": { $in: [2, 7, 4, 5]} 将返回仅包含具有id:2, id:7, id:4 and id:5 的数组的文档。它还将返回具有 id:2, id:8, id:4 and id:5 的数组

标签: java spring mongodb spring-boot spring-data


【解决方案1】:

如果您使用MongoRepository,则创建一个扩展它的接口。示例:

public interface MyRepository extends MongoRepository<Question, String>{

    @Query("{_id: { $in: ?0 } })")
    List<Question> findByIds(List<String> ids, Sort sort);
}

然后在您的服务类或您使用存储库的任何地方。添加以下内容:

Sort sort = new Sort(Direction.ASC,"_id"); // Or DESC
List<Question> questionsById = repository.findByIds(ids, sort);

当然,这里的问题是我创建的一个虚拟类来测试它,用你的替换它。


好的,如果您需要输入用户订单,那么您真的无法使用聚合框架。

如果我的数据库中按该顺序插入了以下数据集:

/* 1 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c5e"),
    "prompt" : "prompt one"
}

/* 2 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c60"),
    "prompt" : "prompt two"
}

/* 3 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c62"),
    "prompt" : "prompt three"
}

/* 4 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c64"),
    "prompt" : "prompt four"
}

那么聚合管道必须如下所示:

db.getCollection('questions').aggregate([{
        "$match": {
            "_id": {
                "$in": [ObjectId("5a103a434d8a2fe38bec5c62"), ObjectId("5a103a434d8a2fe38bec5c60"), ObjectId("5a103a434d8a2fe38bec5c64"), ObjectId("5a103a434d8a2fe38bec5c5e")]
            },
        }
    },
    {
        "$project": {
            "orderByInputId": {
                "$cond": [{
                        "$eq": ["$_id", ObjectId("5a103a434d8a2fe38bec5c62")]
                    },
                    1,
                    {
                        "$cond": [{
                                "$eq": ["$_id", ObjectId("5a103a434d8a2fe38bec5c60")]
                            },
                            2,
                            {
                                "$cond": [{
                                        "$eq": ["$_id", ObjectId("5a103a434d8a2fe38bec5c64")]
                                    },
                                    3,
                                    4
                                ]
                            }
                        ]
                    }
                ]
            },
            prompt: 1
        }
    },

    // Sort the results
    {
        "$sort": {
            "orderByInputId": 1
        }
    }
])

我得到的结果如下:

/* 1 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c62"),
    "prompt" : "prompt three",
    "orderByInputId" : 1.0
}

/* 2 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c60"),
    "prompt" : "prompt two",
    "orderByInputId" : 2.0
}

/* 3 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c64"),
    "prompt" : "prompt four",
    "orderByInputId" : 3.0
}

/* 4 */
{
    "_id" : ObjectId("5a103a434d8a2fe38bec5c5e"),
    "prompt" : "prompt one",
    "orderByInputId" : 4.0
}

【讨论】:

  • 第一部分是正确的,但第二部分是不正确的。我想根据提供 ID 的顺序对问题进行排序。假设用户将问题 ID 值设为 2、4、7,那么我需要以与输入 ID 值相同的顺序对问题进行排序。所以ASC 和DESC 都不能在这里工作。谢谢!
  • 可以在stackoverflow.com/questions/4689914/…找到使用 RDBMS 的类似用例
  • @RavindraRanwala 我更新了答案。如前所述,如果您想要自定义顺序(用户输入顺序),那么您无法使用聚合框架。
  • 是的,谢谢!聚合解决方案似乎更冗长、复杂、可读性更低且不可维护。在服务层进行排序只需要 3 行代码。我会保留它。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
相关资源
最近更新 更多