如何使用Java从Mongodb中的子文档数组中获取所需字段
我刚刚开始使用Mongo Db。下面是我的数据结构 它有一个skillID数组,每个skillID都有一个如何使用Java从Mongodb中的子文档数组中获取所需字段,java,arrays,mongodb,Java,Arrays,Mongodb,我刚刚开始使用Mongo Db。下面是我的数据结构 它有一个skillID数组,每个skillID都有一个activeCampaign数组,每个activeCampaign都有一个callsByTimeZone数组 我在SQL术语中寻找的是: Select activeCampaigns.callsByTimeZone.label, activeCampaigns.callsByTimeZone.loaded from X where skillID=50296 and act
activeCampaign
数组,每个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
数据结构:
{
"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
array下的所有内容。我目前正在解析获得的JSON,只得到PT
值。有没有办法只查询activeCampaigns.callsByTimeZone
中的PT
字段
提前谢谢。很抱歉,如果这个问题已经在论坛上提出,我已经搜索了很多,没有找到合适的解决方案。
提前感谢。将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);
}`
有几种方法可以做到这一点,但您不应该使用字符串操作(即
indexOf
),性能可能会很糟糕
游标中的结果是嵌套映射,表示数据库中的文档-映射是键-值对的良好Java表示。因此,您可以导航到文档中所需的位置,而不必将其作为字符串进行解析。我已经测试了以下内容,它对您的测试数据有效,但如果您的数据与示例不完全相同,则可能需要对其进行调整:
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}
)位于变量中,该变量是我想要的。请注意,这也是一个DBObject,即一个Map,因此如果您想查看其中的内容,需要使用get
:
valuesThatIWant.get("label"); // will return "PT"
valuesThatIWant.get("loaded"); // will return 1
因为DBObject实际上是字符串到对象的映射(即映射
),所以您需要转换从中产生的值(因此我的答案中的第一位代码很难看)-使用数字,这将取决于数据如何加载到数据库中,它可能是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)
)
您还将注意到,您设置的字段
值几乎完全被忽略,结果是文档的大部分,而不仅仅是您要求的字段。我很确定您只能定义希望查询返回的顶级字段,因此您的代码:
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和MongoDB:
- 当您查询数据库时,它将返回您的整个文档
与您的查询匹配的内容,即“skillID”中的所有内容
向下。如果要选择要返回的字段,我认为这些字段将仅为顶级字段。有关更多详细信息,请参阅
- 要导航结果,您需要知道返回了一个
DBObject
s,并且它们实际上是Java中的一个Map
——您可以使用get
导航到正确的节点,
但您需要将值转换为正确的形状
IMO用java编写mongodb查询真是太枯燥了!非常感谢您对游标工作原理的详细解释。在发布这个问题之前,我已经通过使用BasicDBList完成了同样的任务。通过这样做,我猜我实际上会得到整个callsByTimeZone数组,然后将其解析出来,但我的意图是编写一个查询,它可以直接获得标签为PT的元素。我想我需要改变模式来实现同样的效果。我有两个选择,1。通过在activeCampaigns(又称activeCampaigns{callsByTZPacific{},callsByTZEaster{})下创建每个时区的数据作为字段,或2.为CallsbytimeZone创建另一个集合不要使用单独的集合,这违背了MongoDB的目的;您的第一个选项将不起作用,因为您仍然要检索所有activeCampaigns—请记住,“字段”按顶级字段过滤。您可能希望看到的是-这使您能够更好地控制返回的数据。现在,我可以使用$elemMatch将数组元素降低一级//db.activitData.find({“skillID”:50297},{activeCampaigns:{$elemMatch:{“activitid”:11433464}})。这是好的,但它仅限于一个级别$elemMatch不支持向下钻取到数组的数组元素//不要使用单独的集合,这会破坏MongoDb的用途;当查询嵌套结构变得越来越复杂,有时甚至不可能的时候,你能分享一下你的想法吗?为什么我们不应该使用平面结构。