【问题标题】:MongoDB Java Driver Aggregation Framework using $match with $text $search but need $project firstMongoDB Java 驱动程序聚合框架使用 $match 和 $text $search 但首先需要 $project
【发布时间】:2023-03-31 04:00:01
【问题描述】:

docs 备注:

要在 $match 阶段使用 $text,$match 阶段必须是管道的第一阶段。

一些示例 JSON:

{"pid":"b00l16vp", "title": "in our time","categories":{"category1":["factual", "arts culture and the media", "history"]}}
{"pid":"b0079mpp", "title": "doctor who", "categories":{"category2":["childrens", "entertainment and comedy", "animation"],"category1":["signed"]}}
{“pid":"b00htbn3"}
{“pid":"b00gdhqw","categories":{"category2":["factual"],"category3":["scotland"],"category4":["lifestyle and leisure", "food and drink"],"category1":["entertainment", "games and quizzes"]}}

我有以下疑问:

    List<BasicDBObject> pipeline = new ArrayList<>()
            BasicDBObject criteria = new BasicDBObject()
            BasicDBObject theProjections = new BasicDBObject()
            AggregateIterable iterable

    //value is coming from a parameter
        if (value != null) {
    //a text index has been created on the title field
            criteria.put('$text', new BasicDBObject('$search', value))

        }
//cats is coming from a parameter but it will be an array of Strings
if (cats.length != 0) {

            ArrayList<BasicDBObject> orList = new ArrayList<>()
            ArrayList<BasicDBObject> andList = new ArrayList<>()
            BasicDBList theMegaArray = new BasicDBList()


            for (int i = 1; i <= 5; i++) {

                String identifier = "categories.category" + i
                String cleanIdentifier = '$' + identifier
                //If the category does not exist, put in a blank category
                theMegaArray.add(new BasicDBObject('$ifNull', Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST)))
            }
//merges all of the category arrays into 1
            theProjections.put("allCategories", new BasicDBObject('$setUnion', theMegaArray))
            orList.add(new BasicDBObject("allCategories", new BasicDBObject('$all', cats)))

            andList.add(new BasicDBObject('$or', orList))
            criteria.put('$and', andList)
        }
    pipeline.add(new BasicDBObject('$project', theProjections))
    pipeline.add(new BasicDBObject('$match', criteria))


    //and by default
    iterable = collection.aggregate(pipeline)

问题是,如果我想搜索猫,我需要先将投影放在管道中,但如果我想要文本,那么我需要先匹配匹配。有什么办法可以两者兼得吗?

【问题讨论】:

  • 除了聚合管道的第一阶段之外,您不能运行“文本搜索”。这样做的原因非常简单,因为您需要索引,并且在第一阶段之后的任何内容都“可能”改变文档的结构,从而使索引的使用无效。
  • 我在里面看到了$setUnion。您知道您可以将文本索引指向这些数组的所有可能的字段名称。文本搜索本质上适用于所有要指定的字段,因此不需要聚合管道来合并它们。
  • 我希望cats 数组与categories 对象中的内容完全匹配。我相信文本搜索会显示结果,即使它只匹配 1 个词 @NeilLunn

标签: java mongodb aggregation-framework mongo-java-driver


【解决方案1】:

毕竟这是一个非常简单的解决方案。

我创建了一个新的标准对象

BasicDBObject criteriaCat = new BasicDBObject()

为此添加了类别,而不是原来的标准。

criteriaCat.put('$and', andList)

先将 $match 放入管道,然后放入 $project,如果有猫,则在结果上再次运行 $match。

 pipeline.add(new BasicDBObject('$match', criteria))
        pipeline.add(new BasicDBObject('$project', theProjections))

        if (cats.length != 0) {
            pipeline.add(new BasicDBObject('$match', criteriaCat))
        }
        pipeline.add(new BasicDBObject('$sort', sorting))

        //and by default
        iterable = collection.aggregate(pipeline)

【讨论】:

    猜你喜欢
    • 2013-03-10
    • 2015-12-03
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    相关资源
    最近更新 更多