如何使用Java从Mongodb中的子文档数组中获取所需的字段

时间:2014-01-23 01:00:41

标签: java arrays mongodb

我刚刚开始使用Mongo Db。以下是我的数据结构。

它有一个技能ID数组,每个数组都有一个activeCampaigns数组,每个activeCampaign都有一个数组callsByTimeZone

我在SQL术语中寻找的是:

Select activeCampaigns.callsByTimeZone.label,
       activeCampaigns.callsByTimeZone.loaded 
from X 
where skillID=50296 and activeCampaigns.campaign_id= 11371940 
      and activeCampaigns.callsByTimeZone='PT'

我期待的输出是

{"label":"PT", "loaded":1 }

我使用的命令是

db.cd.find({ "skillID" : 50296 , "activeCampaigns.campaignId" : 11371940,
"activeCampaigns.callsByTimeZone.label" :"PT" },
{ "activeCampaigns.callsByTimeZone.label" : 1 , 
"activeCampaigns.callsByTimeZone.loaded" : 1 ,"_id" : 0})

我得到的结果是activeCampaigns.callsByTimeZone下的所有内容,而我只期待PT

DataStructure:

{
   "skillID":50296,
   "clientID":7419,
   "voiceID":1,
   "otherResults":7,
   "activeCampaigns":
   [{
       "campaignId":11371940,
       "campaignFileName":"Aaron.name.121.csv",
       "loaded":259,
       "callsByTimeZone":
       [{
           "label":"CT",
           "loaded":6
       },
       {
           "label":"ET",
           "loaded":241
       },
       {
           "label":"PT",
           "loaded":1
       }]
   }]
}

我在Java中尝试过相同的东西。

QueryBuilder query = QueryBuilder.start().and("skillID").is(50296)
                    .and("activeCampaigns.campaignId").is(11371940)
                    .and("activeCampaigns.callsByTimeZone.label").is("PT");

BasicDBObject fields = new BasicDBObject("activeCampaigns.callsByTimeZone.label",1)
                    .append("activeCampaigns.callsByTimeZone.loaded",1).append("_id", 0);

DBCursor cursor = coll.find(query.get(), fields);
String campaignJson = null;
while(cursor.hasNext()) {
    DBObject campaignDBO = cursor.next();
    campaignJson = campaignDBO.toString();
    System.out.println(campaignJson);
}

获得的值是callsByTimeZone数组下的所有内容。我目前正在解析获得的JSON并仅获取PT个值。有没有办法只查询PT内的activeCampaigns.callsByTimeZone字段。

先谢谢。如果这个问题已经在论坛中提出,我已经搜索了很多,但未能找到合适的解决方案。 提前谢谢。

2 个答案:

答案 0 :(得分:1)

有几种方法可以做到这一点,但你不应该使用字符串操作(即indexOf),性能可能会很糟糕。

cursor中的结果是嵌套的Maps,表示数据库中的文档 - Map是键值对的良好Java表示。因此,您可以导航到文档中所需的位置,而不必将其解析为String。我已经测试了以下内容,它可以处理您的测试数据,但如果您的数据与示例完全不同,则可能需要进行调整:

while (cursor.hasNext()) {
    DBObject campaignDBO = cursor.next();
    List callsByTimezone = (List) ((DBObject) ((List) campaignDBO.get("activeCampaigns")).get(0)).get("callsByTimeZone");
    DBObject valuesThatIWant;
    for (Object o : callsByTimezone) {
        DBObject call = (DBObject) o;
        if (call.get("label").equals("PT")) {
            valuesThatIWant = call;
        }
    }
}

根据您的数据,您可能还希望针对空值添加保护。

您要查找的内容({"label":"PT", "loaded":1 })位于变量valueThatIWant中。请注意,这也是一个DBObject,即Map,所以如果你想看看里面有什么,你需要使用get

valuesThatIWant.get("label");  // will return "PT"
valuesThatIWant.get("loaded"); // will return 1

因为DBObject实际上是一个String to Object的映射(即Map<String, Object>),你需要转换它出来的值(因此在我的答案的第一位代码中的丑陋) - 用数字,它将取决于数据如何加载到数据库中,它可能以int或double形式出现:

String theValueOfLabel = (String) valuesThatIWant.get("label");   // will return "PT"
double theValueOfLoaded = (Double) valuesThatIWant.get("loaded"); // will return 1.0

我还想从我的回答中指出以下内容:

((List) campaignDBO.get("activeCampaigns")).get(0)

这假设“activeCampaigns”是a)一个列表,在这种情况下b)只有一个条目(我正在做get(0))。

您还会注意到,您设置的fields值几乎完全被忽略,结果是大部分文档,而不仅仅是您要求的字段。我很确定你只能定义你希望查询返回的顶级字段,所以你的代码是:

BasicDBObject fields = new BasicDBObject("activeCampaigns.callsByTimeZone.label",1)
    .append("activeCampaigns.callsByTimeZone.loaded",1)
    .append("_id", 0);

实际上与:

完全相同
BasicDBObject fields = new BasicDBObject("activeCampaigns", 1).append("_id", 0);

我认为一些有助于您使用Java和Java的要点。 MongoDB是:

  • 当您查询数据库时,它将返回您的整个文档 与您的查询匹配的东西,即“skillID”中的所有内容 向下。如果要选择要返回的字段,我认为这些只是顶级字段。有关详细信息,请参阅the documentation
  • 要导航结果,您需要知道返回DBObject,并且这些实际上是Java中的Map<String, Object> - 您可以使用get导航到正确的节点, 但是你需要将值转换成正确的形状。

答案 1 :(得分:0)

使用下面的Java代码替换while循环似乎将“PT”作为输出。

   `while(cursor.hasNext()) {
        DBObject campaignDBO = cursor.next();
        campaignJson = campaignDBO.get("activeCampaigns").toString();
        int labelInt = campaignJson.indexOf("PT", -1);
        String label = campaignJson.substring(labelInt, labelInt+2);
        System.out.println(label);
      }`