【问题标题】:How can I compose a query such as (A || B || C) && (X || Y) in MongoDB Java Driver 3.2如何在 MongoDB Java Driver 3.2 中编写查询,例如 (A || B || C) && (X || Y)
【发布时间】:2016-10-12 14:41:17
【问题描述】:

不幸的是,我找不到 Mongo 3.2 java 驱动程序的示例,用于查询“(A 或 B 或 C)和(D 或 E 或 F 或 G)”

括号内的参数数量是可变的 - 最多一百

我找到了“(A && B) || (X && Y)”的示例,但它对我没有帮助。

How to execute queries with both AND and OR clauses in MongoDB with Java

我的代码产生错误:

MongoQueryException:查询失败,错误代码 2 和错误消息“$or/$and/$nor 条目需要是完整对象”

List<Document> docs = new ArrayList<>();

for (Integer ln: input.getLastnames()) {
        docs.add(new Document("lastname",ln));
    }

    Document queryLN = new Document(
            "$or", Arrays.asList(docs)
    );

    docs.clear();
    for (Integer fn: input.getFirstnames()) {
        docs.add(new Document("firstname",fn));
    }

    Document queryFN = new Document(
            "$or", Arrays.asList(docs)
    );

    Document query = new Document(
            "$and", Arrays.asList(queryFN,queryLN));

    List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());

【问题讨论】:

  • 在您的情况下,Arrays.asList(List&lt;Document&gt;) 产生 List&lt;List&lt;ListDocument&gt;&gt;。在您引用的示例中,它是List&lt;Document&gt;。我会怪罪的。
  • 将 Arrays.asList(docs) 更改为 docs 消除了错误,但结果不在(A 或 B)和(C 或 D)附近。 A 或 B 或 C 或 D 的排序。@saurav 的建议是完整的。非常感谢。

标签: java mongodb


【解决方案1】:

当您有很长的未知 OR 条件列表时,您应该在这种条件下使用“in”查询。

示例代码:

try {
        MongoClient mongo = new MongoClient();
        DB db = mongo.getDB("so");
        DBCollection coll = db.getCollection("employees");

        List<Integer> ageList = new ArrayList<>();
        ageList.add(30);
        ageList.add(35);

        List<String> nameList = new ArrayList<>();
        nameList.add("Anna");

        BasicDBObject query = new BasicDBObject("$and", Arrays.asList(
            new BasicDBObject("age", new BasicDBObject("$in", ageList)),
            new BasicDBObject("name", new BasicDBObject("$in", nameList)))
        );

        DBCursor cursor = coll.find(query);
        while(cursor.hasNext()) {
            System.out.println(cursor.next());
        }
}catch (Exception ex){
        ex.printStackTrace();
}

要试验上述代码,您可以在 MongoDB 中添加以下条目:

db.employees.insert({"name":"Adma","dept":"Admin","languages":["german","french","english","hindi"],"age":30, "totalExp":10});
db.employees.insert({"name":"Anna","dept":"Admin","languages":["english","hindi"],"age":35, "totalExp":11});
db.employees.insert({"name":"Bob","dept":"Facilities","languages":["english","hindi"],"age":36, "totalExp":14});
db.employees.insert({"name":"Cathy","dept":"Facilities","languages":["hindi"],"age":31, "totalExp":4});
db.employees.insert({"name":"Mike","dept":"HR","languages":["english", "hindi", "spanish"],"age":26, "totalExp":3});
db.employees.insert({"name":"Jenny","dept":"HR","languages":["english", "hindi", "spanish"],"age":25, "totalExp":3});

上面的代码产生了这个查询:

db.employees.find({"$and":[{"age":{"$in":[30, 35]}},{"name":{"$in":["Anna"]}}]});

输出是:

{ "_id" : { "$oid" : "57ff3e5e3dedf0228d4862ad"} , "name" : "Anna" , "dept" : "Admin" , "languages" : [ "english" , "hindi"] , "age" : 35.0 , "totalExp" : 11.0}

关于这个主题的一篇好文章:https://www.mkyong.com/mongodb/java-mongodb-query-document/

也请阅读:https://stackoverflow.com/a/8219679/3896066https://stackoverflow.com/a/14738878/3896066

【讨论】:

  • 非常感谢,saurav!很抱歉,这笔赏金不能分割。 4J41-s 的回答稍晚一些,但更加个人化。不能忽视这一点。
【解决方案2】:

让我们首先了解您的代码。我们将通过用简单语句替换 for 循环并添加一些打印语句来使其变得简单。

List<Document> docs = new ArrayList<>();

docs.add(new Document("lastname","Walker"));
docs.add(new Document("lastname","Harris"));    

Document queryLN = new Document("$or", Arrays.asList(docs));

docs.clear();

System.out.println(queryLN.toJson());//{ "$or" : [[]] } 

docs.add(new Document("firstname", "Pat"));
docs.add(new Document("firstname", "Matt"));

Document queryFN = new Document("$or", Arrays.asList(docs));

System.out.println(queryLN.toJson());//{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }
System.out.println(queryFN.toJson());//{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }

Document query = new Document("$and", Arrays.asList(queryFN, queryLN));

System.out.println(query.toJson());//{ "$and" : [{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }, { "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }] }

List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());

观察:

  • docs 已经是一个列表。在docs 上使用Arrays.asList,会创建一个列表列表,这对于$and, $or, $nor 是不可接受的。这些运算符接受list of Documents。这解释了错误消息。

  • Arrays.asList 不会创建它接收到的数组或列表的副本。它只是在它上面创建一个包装器。此外,new document() 不会复制它使用“$or”接收的列表,只是引用原始列表。因此,调用docs.clear() 将重置$orqueryLN 中的内容。

  • 此外,上述概念解释了为什么第二个和第三个打印语句给出相同的输出。

让我们现在开始运行代码。

List<Document> docsLN = new ArrayList<Document>();
List<Document> docsFN = new ArrayList<Document>();

for (Integer ln: input.getLastnames()) {
    docsLN.add(new Document("lastname",ln));
}           

Document queryLN = new Document("$or", docsLN);

for (Integer fn: input.getFirstnames()) {
    docsFN.add(new Document("firstname",fn));
}

Document queryFN = new Document("$or", docsFN);

System.out.println(queryLN.toJson());
System.out.println(queryFN.toJson());

Document query = new Document("$and", Arrays.asList(queryFN, queryLN));

System.out.println(query.toJson());
List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());

另外,请考虑将$or 替换为$in

来自docs

当使用 $or 时,这是对 相同字段的值,使用 $in 运算符而不是 $or 运算符。

【讨论】:

  • 非常感谢您查看我可耻的代码并指出其他错误!
猜你喜欢
  • 1970-01-01
  • 2021-04-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 2013-05-26
  • 2019-08-19
  • 1970-01-01
相关资源
最近更新 更多