MongoError: key $ must not start with '$' when store JSON object generated by xml2js module

MongoError: key $ must not start with '$' when store JSON object generated by xml2js module

各位,

MongoDB db.version() is 3.0.5
mongodb package.json shows 2.0.42 version
xml2js package.json shows 0.4.9 version  

我已经用谷歌搜索了这个错误,并通读了所有现有的问题,none 似乎符合我的情况(jira issue, nor the google group discussions 等)。这可能与 mongodb 原生 driver(或 MongoDB 服务器版本)、xml2js 或其他东西有关。

我做了很多测试,确实找到了解决问题的方法,但我很想知道问题出在哪里。

我有一个应用可以执行以下操作:

  1. 将 XForm (survey.xml) 上传到 ExpressJS
  2. 使用 xml2js 库将 XML 转换为 JSON object(示例如下)
  3. 遍历2中创建的JSON object并删除不需要的字段(代码段如下所示)
  4. 使用 mongodb 原生 driver
  5. 将 3 中修改后的 JSON object 推送到 MongoDB

第 4 步因错误而失败(显示在问题的标题中)。

  1. 有 2 个 JSON object,一个是调查表,包含 $ 键但是,在我将文档插入 mongodb 之前,我删除了$ 键使用以下代码

    (function traverse(o) {
    for (var i in o) {
      if (o[i] !== null && typeof(o[i])=="object") {
          //going on step down in the object tree!!
        if(o[i].$) {
          var ref = "";
          if(o[i].$.ref) {
            ref = o[i].$.ref;
          } else if (o[i].$.nodeset) {
            ref = o[i].$.nodeset;
          }
          o[i].ref = ref;
          o[i].$ = undefined;
          var chunks = ref.split('/');
          o[i]['name'] = chunks[chunks.length - 1];
        }
        traverse(o[i]);
      }
    }
    })(body);
    
  2. 我在将上面的输出添加到 MongoDB 之前控制台记录了上面的输出,并且 console.log 没有显示带 $ 的键的符号。

  3. 假设第 2 步实际上由于密钥中的 $ 而失败,这是不正确的,我有另一个 JSON 这是调查的响应并且不包含任何 $,但这也因相同的错误而失败(Mongo错误:键 $ 不得以“$”开头)。

    db.collection('submissions').insert(jsonObject, function(err, result) {
      if(err) console.log('error is : ' + err);
      console.log('insertion result : ' + JSON.stringify(result));
    });
    

下面是XML表单提交

   <?xml version='1.0' ?>
   <ppe id="ppe_checklist_new">
    <starting_repeat>
        <location>dark_room</location>
        <ppe_dark>safety_glasses</ppe_dark>
        <xyz_group>
            <condition>condition_missing</condition>
            <test_condition>b</test_condition>
        </xyz_group>
    </starting_repeat>
    <starting_repeat>
        <location>nitrogen_store</location>
        <ppe_nitrogen>leather_gloves_s</ppe_nitrogen>
        <xyz_group>
            <condition>condition_replacing</condition>
            <test_condition />
        </xyz_group>
    </starting_repeat>
    <starting_repeat>
        <location>nitrogen_store</location>
        <ppe_nitrogen>blue_gloves_m</ppe_nitrogen>
        <xyz_group>
            <condition />
            <test_condition>b</test_condition>
        </xyz_group>
    </starting_repeat>
    <starting_repeat>
        <location>cold_room_first</location>
        <ppe_cold>hearing_muff_1</ppe_cold>
        <xyz_group>
            <condition>condition_ok</condition>
            <test_condition>f</test_condition>
        </xyz_group>
    </starting_repeat>
    <sample_group>
        <date>2015-08-24</date>
        <random_number>55</random_number>
    </sample_group>
    <another_group>
        <another_repeat>
            <sample_text>Sample text 1</sample_text>
            <image />
        </another_repeat>
        <another_repeat>
            <sample_text>Sample text 2</sample_text>
            <image />
        </another_repeat>
    </another_group>
    <form_done>OK</form_done>
    <survey_start>2015-08-24T16:55:23.185+01</survey_start>
    <survey_end>2015-08-24T16:57:24.460+01</survey_end>
    <survey_day>2015-08-24</survey_day>
    <survey_device>353490061313389</survey_device>
    <meta>
        <instanceID>uuid:2aba0eff-5350-47e3-9e9c-9606d2c9e7d6</instanceID>
    </meta>
</ppe>

我将以上内容提供给具有以下配置的 xml2js 模块:

function parseXMLToJS(filename, path, callback) {
  var parser = new xml2js.Parser({explicitArray:false});
  var fileURL = path + filename;

  var data = fs.readFile(fileURL, function(err, data) {
    if(err) {
      logger.error('Error reading submission file. Error %', err);
    } else {
      parser.parseString(data, function (err, result) {
        if(err) {
          logger.error('Error parsing XML to JS. Error : %',  err);
          callback({parsed:false, result:result});
        } else {
          callback({parsed:true, result:result});
        }
      });
    }
  });
}

模块生成JSONobject如下图:

{
    "ppe": {
        "starting_repeat": [
            {
                "location": "dark_room",
                "ppe_dark": "safety_glasses",
                "xyz_group": {
                    "condition": "condition_missing",
                    "test_condition": "b"
                }
            },
            {
                "location": "nitrogen_store",
                "ppe_nitrogen": "leather_gloves_s",
                "xyz_group": {
                    "condition": "condition_replacing",
                    "test_condition": ""
                }
            },
            {
                "location": "nitrogen_store",
                "ppe_nitrogen": "blue_gloves_m",
                "xyz_group": {
                    "condition": "",
                    "test_condition": "b"
                }
            },
            {
                "location": "cold_room_first",
                "ppe_cold": "hearing_muff_1",
                "xyz_group": {
                    "condition": "condition_ok",
                    "test_condition": "f"
                }
            }
        ],
        "sample_group": {
            "date": "2015-08-24",
            "random_number": "55"
        },
        "another_group": {
            "another_repeat": [
                {
                    "sample_text": "Sample text 1",
                    "image": ""
                },
                {
                    "sample_text": "Sample text 2",
                    "image": ""
                }
            ]
        },
        "form_done": "OK",
        "survey_start": "2015-08-24T16:55:23.185+01",
        "survey_end": "2015-08-24T16:57:24.460+01",
        "survey_day": "2015-08-24",
        "survey_device": "353490061313389",
        "id": "ppe_checklist_new",
        "uuid": "2aba0eff-5350-47e3-9e9c-9606d2c9e7d6"
    }
}

我尝试检查我插入到 MongoDB 的数据是否是 object,结果是。

typeof(result.result)
  1. 尝试通过 Mongo Shell 从 xml2js 插入生成的 JSON object 并且成功了。
  2. 尝试在我的 javascript 代码中创建一个 JS object,其内容与由 xml2js 生成的 JSON 相同,并通过 [=105= 将其插入 MongoDB ] native driver 有效(尽管我比较了两个 JSON 并且它们完全相同)。

总之,我可以说mongodb原生driver不喜欢xml2js模块生成的JSONobject,为什么我不知道?我等不及要知道了。我尝试了以下解决方法

  1. 使用 xml2js
  2. 转换 XML 2 JSON
  3. 将 xml2js 返回的 JSON object 字符串化 (x = JSON.stringify(obj);)
  4. 解析字符串化的 JSON object 返回 (parsedX = JSON.parse(x);)
  5. 通过 mongodb 本机驱动器将解析后的值插入到 MongoDB 中,并且成功了。

不管是什么问题,上面的错误消息都具有误导性,或者可能不适合导致它的问题。我找不到获得更详细错误的方法(也许 mongodb 可以提供更多解释,很想知道)。

感谢您的耐心等待。

traverse 函数的下一行只是将 $ 字段设置为 undefined 的值,而没有实际删除它。

o[i].$ = undefined;

更改该行以使用 delete 来删除它:

delete o[i].$;

您使用 JSON.stringifyJSON.parse 的解决方法有效,因为 undefined 值无法在 JSON 中表示,因此 JSON.stringify 调用删除字段该值。