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

Posted

技术标签:

【中文标题】MongoError:存储由 xml2js 模块生成的 JSON 对象时,键 $ 不能以 \'$\' 开头【英文标题】:MongoError: key $ must not start with '$' when store JSON object generated by xml2js moduleMongoError:存储由 xml2js 模块生成的 JSON 对象时,键 $ 不能以 '$' 开头 【发布时间】:2015-11-19 02:50:27 【问题描述】:

大家,

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

我已经用谷歌搜索了该错误,并阅读了所有现有问题,但似乎没有一个问题与我的情况相匹配(jira issue 和 google group discussions 都不是)。这可能与 mongodb 本机驱动程序(或 MongoDB 服务器版本)、xml2js 或其他有关。

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

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

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

第 4 步失败并出现错误(如问题标题所示)。

    有 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);
    

    在将上面的输出添加到 MongoDB 之前,我控制台记录了上面的输出,并且 console.log 没有显示带有 $ 的键的迹象。

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

    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);
        
      );
    
  );

模块生成如下所示的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"
    

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

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

总之,我可以说mongodb原生驱动不喜欢xml2js模块生成的JSON对象,为什么我不知道呢?我迫不及待想知道。我尝试了以下解决方法

    使用 xml2js 转换 XML 2 JSON 字符串化从 xml2js 返回的 JSON 对象 (x = JSON.stringify(obj);) 将字符串化的 JSON 对象解析回来 (parsedX = JSON.parse(x);) 通过 mongodb 原生驱动将解析后的值插入到 MongoDB 中,并且成功了。

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

感谢您的时间和耐心。

【问题讨论】:

嗯,解析对象的第一行基本上是 "ppe": "$": "id": "ppe_checklist_new" ,,这无疑是问题的根源。关键是你不能从下一个元素"starting_repreat": [ 开始工作吗?或者甚至只是 "ppe": "$": 下的所有内容?您也可能真的不希望将其作为数据库的原始输入。毕竟它是一个“数据库”,而不是一个 XML 文件。所以这里还有其他的考虑。 尝试将o[i].$ = undefined; 行更改为delete o[i].$;; @JohnnyHK 欢呼,删除成功了。我很好奇 JSON.stringify() 后跟 JSON.parse() 方法的工作原理。考虑到这个问题,这些方法对 JSON 对象有什么特别的作用吗? 是的,undefined 值不能用 JSON 表示,因此JSON.stringify 将删除具有该值的所有字段。 @BlakesSeven 如果我在 ppe 之后使用,那么我会错过一些字段(form_done、survey_start 等)。你说的生是什么意思?我绝对不会将上面显示的 JSON 插入数据库,在这种情况下,整数、日期也会以字符串形式结束。我将修改 JSON,以便使用 MongoDB 数据类型存储所有非字符串字段。对不起,我的意思是这个 MongoDB。感谢您的评论。 【参考方案1】:

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

o[i].$ = undefined;

更改该行以使用delete 将其删除:

delete o[i].$;

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

【讨论】:

以上是关于MongoError:存储由 xml2js 模块生成的 JSON 对象时,键 $ 不能以 '$' 开头的主要内容,如果未能解决你的问题,请参考以下文章

MongoError:升级猫鼬模块后处于无效状态的服务器实例未定义

MongoError:虚线字段..对存储无效

(节点:52213)警告:在循环依赖中访问模块导出的不存在属性“MongoError”(使用节点--trace-warnings

Promisifying xml2js 解析函数(ES6 Promises)

ReferenceError:全局未在xml2js中定义

node js xml cdata