【问题标题】:How to use two conditon in one array?如何在一个数组中使用两个条件?
【发布时间】:2014-08-13 10:55:53
【问题描述】:

我有一个存储在 Mongo 中的任务列表,如下所示

{
"name": "task1",
"requiredOS": [
    {
        "name": "linux",
        "version": [
            "6.0"
        ]
    },
    {
        "name": "windows",
        "version": [
            "2008",
            "2008R2"
        ]
    }
],
"requiredSW": [
    {
        "name": "MySQL",
        "version": [
            "1.0"
        ]
    }
]
}

我的目的是按操作系统和软件过滤任务,例如用户给我下面的过滤条件

{
"keyword": [
    {
        "OS": [
            {
                "name": "linux", 
                "version": [
                    "6.0"
                ]
            }, 
            {
                "name": "windows", 
                "version": [
                    "2008"
                ]
            }
        ]
    }, 
    {
        "SW": [ ]
    }
]

}

我需要通过搜索“requiredOS”和“requiredSW”字段来过滤掉所有可以在windows2008和Linux 6.0上运行的任务。如您所见,搜索条件是一个数组(“OS”部分)。使用数组作为搜索条件时我遇到了麻烦。我希望查询返回一个满足条件的任务列表。

一个具有挑战性的事情是我需要使用 @Query 将查询集成到 spring-data 中。所以查询必须参数化

谁能帮帮我?

我尝试了一个查询,但没有返回任何内容。我的目的是使用 $all 将两个条件组合在一起,然后使用 $elemMatch 搜索“requiredOS”字段

{"requiredOS":{"$elemMatch":{"$all":[{"name":"linux","version":"5.0"},{"name":"windows","version":"2008"}]}}}

【问题讨论】:

  • 我认为您没有清楚地说明您期望匹配的是什么,甚至没有说明您期望的结果。您的问题可以详细说明您希望您的“测试”查询返回某个结果,并且还显示可以返回该结果的一些数据。目前这些条件都不成立。
  • 很抱歉没有说明清除。目前我在Mongo中存储了一些“Task”,json结构如第一段代码所示。我想匹配“requiredOS”和“requiredSW”数组字段。搜索条件就像第 2 节中的 json。它也是任何数组(“OS”部分)。所以我不是很清楚如何使用数组作为搜索条件。我现在说清楚了吗?
  • 并非如此。正如我所说,您的“样本”可能与您的条件不符,因此人们很难理解。我可以猜测您试图匹配空数组的“条件”。但实际上你的整个意图并不清楚。使用问题上的“编辑”链接并在对有兴趣提供帮助的人发表评论之前进行澄清。这就是 cmets 的用途,“问题”是您陈述意图的地方,而不是 cmets。
  • 当他说他的purpose is to filter the task by OS and Software 时,我认为他的问题已经说得很清楚了。很明显,他想findrequiredOSrequiredSW 数组中查询中提到的所有指定值的所有文档。
  • @NeilLunn 感谢提醒。我已经更新了我的问题。

标签: spring mongodb spring-data


【解决方案1】:

如果我正确理解您的尝试,您需要使用 $elemMatch 运算符:

http://docs.mongodb.org/manual/reference/operator/query/elemMatch/#op._S_elemMatch

以您的示例为例,查询应如下所示: @Query("{'requiredOS':{$elemMatch:{name:'linux', version:'7.0'},$elemMatch:{name:'windows', version:'2008'}}}")

它与您提供的文件相匹配。

【讨论】:

  • 我认为你的代码行不通,因为如果你在同一个查询的文档或子文档中使用同一个运算符两次,则只保留最后一个运算符的出现。在这种情况下,您的查询相当于:{requiredOS: {$elemMatch: {name: "windows", version: 2008}}}
  • 是的,我已经测试了查询。它确实会保留最后一个运算符。
【解决方案2】:

您基本上似乎需要将您的“参数”转换为产生结果的查询表单,而不是直接传递它们。这是一个示例“翻译”,其中“空”数组被认为与“任何东西”匹配。

此外,其他条件也不会“从字面上”直接通过。这样做的原因是,在这种形式下,MongoDB 认为它意味着“精确匹配”。因此,您想要的是组合多个数组条件的 $elemMatch 运算符和组合同一属性元素上的条件的 $and 运算符。

这比$all 长一点,但本质上是因为该运算符是$and 的“缩短”形式,因为$in$or

db.collection.find({
    "$and": [
        {
            "requiredOS": { 
                "$elemMatch": {
                    "name": "linux",
                    "version": "6.0"
                 }
            }
        },
        {
            "requiredOS": {
                "$elemMatch": {
                    "name": "windows",
                    "version": "2008"
                }
            }
        }
    ]
})

因此,只需将请求中的属性转换为实际匹配所需的查询表单即可。

可以通过多种方式将其构建到查询对象中,例如使用查询构建器:

    DBObject query = new Query(
        new Criteria().andOperator(
            Criteria.where("requiredOS").elemMatch(
                Criteria.where("name").is("linux").and("version").is("6.0")
            ),
            Criteria.where("requiredOS").elemMatch(
                Criteria.where("name").is("windows").and("version").is("2008")
            )
        )
    ).getQueryObject();

然后您可以将其作为查询对象或任何其他接受查询对象的方法传递给 mongoOperations 方法。

【讨论】:

  • 我明白你的意思。最后一个问题。你知道如何使用 mongoTemplate 在 java 中执行 json。 executeCommand() 函数只能运行 mongo 命令。 executeQuery() 函数只能运行 Query 对象
  • @XiranLi 这只是用你的标准构造一个查询对象的问题。这可以使用 BasicDBObject 或任何可用的构建器来完成,如图所示。
猜你喜欢
  • 2022-10-13
  • 2016-06-26
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-21
  • 1970-01-01
  • 2015-02-23
相关资源
最近更新 更多