MongoError:存储由 xml2js 模块生成的 JSON 对象时,键 $ 不得以“$”开头

Raf*_*Raf 5 xml json mongodb node.js node-mongodb-native

每个人,

MongoDB db.version() is 3.0.5
mongodb package.json shows 2.0.42 version
xml2js package.json shows 0.4.9 version  
Run Code Online (Sandbox Code Playgroud)

我已经用谷歌搜索了错误,并通读了所有现有的问题,似乎没有一个与我的情况相符(既不是jira 问题,也不是谷歌小组讨论等)。这可能与 mongodb 本机驱动程序(或 MongoDB 服务器版本)、xml2js 或其他内容有关。

我已经进行了大量测试并确实找到了解决问题的方法,但是,我很想知道问题出在哪里。

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

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

第 4 步失败并出现错误(显示在问题标题中)。

  1. 有 2 个 JSON 对象,一个是调查表单,包含 $ 键,但是,在我将文档插入 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);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在将上面的输出添加到 MongoDB 之前,我控制台记录了上面的输出,并且 console.log 没有显示带有 $ 的键的迹象。

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

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

下面是 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>
Run Code Online (Sandbox Code Playgroud)

我使用以下配置将上述内容提供给 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});
        }
      });
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

并且模块生成一个 JSON 对象,如下所示:

{
    "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"
    }
}
Run Code Online (Sandbox Code Playgroud)

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

typeof(result.result)
Run Code Online (Sandbox Code Playgroud)
  1. 尝试通过 Mongo Shell 从 xml2js 插入生成的 JSON 对象,并且成功了。
  2. 尝试在我的 javascript 代码中创建一个与 xml2js 生成的 JSON 内容相同的 JS 对象,并通过 mongodb 本机驱动程序将其插入到 MongoDB 中(即使我比较了两个 JSON 并且它们完全相同)。

总之,我可以说 mongodb 本机驱动程序不喜欢由 xml2js 模块生成的 JSON 对象,为什么我不知道?我等不及要知道了。我尝试了以下解决方法

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

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

感谢您的时间和耐心。

Joh*_*yHK 3

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

o[i].$ = undefined;
Run Code Online (Sandbox Code Playgroud)

更改该行以delete将其删除:

delete o[i].$;
Run Code Online (Sandbox Code Playgroud)

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