检索嵌套文档的特定元素

时间:2017-08-04 00:42:31

标签: mongodb mongodb-query aggregation-framework

只是想不出来。这是来自MongoDB作业的文档格式,它源自我无法控制的布局的XML文件:

{
    "reference" : [ "93417" ],
    "Title" : [ "RN - Pediatric Director of Nursing" ],
    "Description" : [ "...a paragraph or two..." ],
    "Classifications" : [ 
        {
            "Classification" : [ 
                {
                    "_" : "Nurse / Midwife",
                    "name" : [ "Category" ]
                }, 
                {
                    "_" : "FL - Jacksonville",
                    "name" : [ "Location" ],
                }, 
                {
                    "_" : "Permanent / Full Time",
                    "name" : [ "Work Type" ],
                }, 
                {
                    "_" : "Some Health Care Org",
                    "name" : [ "Company Name" ],
                }
            ]
        }
    ],
    "Apply" : [ 
        {
            "EmailTo" : [ "jess@recruiting.co" ]
        }
    ]
}

目的是从数据库中提取作业列表,以包含“位置”,该位置被隐藏在“Classifications.Classification ._”的第二个文档中。

我尝试了$ project,$ unwind,$ match,$ filter,$ group的各种'聚合'排列......但我似乎没有得到任何结果。尝试只检索公司名称,我希望这可以工作:

db.collection(JOBS_COLLECTION).aggregate([
    { "$project" : { "meta": "$Classifications.Classification" } },
    { "$project" : { "meta": 1, _id: 0 } },
    { "$unwind" : "$meta" },
    { "$match": { "meta.name" : "Company Name" } },
    { "$project" : { "Company" : "$meta._" } },
])

但是这会为每条记录提供所有内容,因此:

[{
    "Company":[
        "Nurse / Midwife",
        "TX - San Antonio",
        "Permanent / Full Time",
        "Some Health Care Org"
    ]
}, { etc etc }]

我错过了什么或滥用了什么?

1 个答案:

答案 0 :(得分:0)

理想情况下,使用MongoDB 3.4,您只需$project,并使用$map$filter$reduce的数组运算符。后者为" compact"数组和前者要提取相关的元素和细节。同样$arrayElemAt仅使用"元素"来自数组:

db.collection(JOBS_COLLECTION).aggregate([
  { "$match": { "Classifications.Classification.name": "Location" } },
  { "$project": {
    "_id": 0,
    "output": {
      "$arrayElemAt": [
        { "$map": {
          "input": {
            "$filter": {
              "input": {
                "$reduce": {
                  "input": "$Classifications.Classification",
                  "initialValue": [],
                  "in": {
                    "$concatArrays": [ "$$value", "$$this" ]    
                  }
                }
              },
              "as": "c",
              "cond": { "$eq": [ "$$c.name", ["Location"] ] }        
            }
          },
          "as": "c",
          "in": "$$c._"
        }},
        0
      ]
    }
  }}
])

甚至可以跳过$reduce只是将$concatArrays应用于"合并"并简单地抓住第一个"数组索引(因为只有一个)使用$arrayElemAt

db.collection(JOBS_COLLECTION).aggregate([
  { "$match": { "Classifications.Classification.name": "Location" } },
  { "$project": {
    "_id": 0,
    "output": {
      "$arrayElemAt": [
        { "$map": {
          "input": {
            "$filter": {
              "input": { "$arrayElemAt": [ "$Classifications.Classification", 0 ] },
              "as": "c",
              "cond": { "$eq": [ "$$c.name", ["Location"] ] }        
            }
          },
          "as": "c",
          "in": "$$c._"
        }},
        0
      ]
    }
  }}
])

这使得操作与MongoDB 3.2兼容,你应该"应该"至少跑步。

这反过来允许您根据" first"的初始输入变量,使用$indexOfArray考虑​​MongoDB 3.4的替代语法。数组索引使用$let来缩短语法:

db.collection(JOBS_COLLECTION).aggregate([
  { "$match": { "Classifications.Classification.name": "Location" } },
  { "$project": {
    "_id": 0,
    "output": {
      "$let": {
        "vars": {
          "meta": {
            "$arrayElemAt": [
              "$Classifications.Classification",
              0
            ]
          }
        },
        "in": {
          "$arrayElemAt": [
            "$$meta._",
            { "$indexOfArray": [ 
              "$$meta.name", [ "Location" ]
            ]}  
          ]     
        }
      }
    }
  }}
])

如果确实你认为那是"更短"那就是。

在另一种意义上,就像上面有一个"数组内部和数组",所以为了处理它,你$unwind 两次,实际上$concatArrays $reduce内部的9在理想情况下正在反击:

db.collection(JOBS_COLLECTION).aggregate([
  { "$match": { "Classifications.Classification.name": "Location" } },
  { "$unwind": "$Classifications" },
  { "$unwind": "$Classifications.Classification" },
  { "$match": { "Classifications.Classification.name": "Location" } },
  { "$project": { "_id": 0, "output": "$Classifications.Classification._" } }
])

所有陈述实际产生:

{
    "output" : "FL - Jacksonville"
}

由原始意图选择的"_"内部数组元素中"Location"的匹配值。

请注意,所有语句的前面应该是相应的[$match] {{3}}语句,如下所示:

{ "$match": { "Classifications.Classification.name": "Location" } },

由于没有它,您可能会不必要地处理文档,这实际上不包含与该条件匹配的数组元素。当然,由于文件的性质,情况可能并非如此,但确保"初始"通常是一种良好的做法。选择始终与您稍后打算提取的详细信息相匹配,并提取"。

所有这些都说,即使这是从XML直接导入的结果,也应该更改结构,因为它不能有效地呈现查询。 MongoDB文档不适用于XPATH在发出查询方面的工作方式。因此,任何事情" XML Like"不会是一个好的结构,如果" import"过程不能改变为更适应的格式,那么至少应该有一个"后期处理"以更实用的形式将其操作到一个单独的存储中。