104

mongo では、ドット (.) またはドル記号 ($) を使用したキーの挿入が許可されていないようですが、mongoimport ツールを使用してドットを含む JSON ファイルをインポートすると、正常に機能しました。ドライバーは、その要素を挿入しようとしていると不平を言っています。

データベース内のドキュメントは次のようになります。

{
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {
        "9.7x": [
            2007,
            2008,
            2009,
            2010
        ]
    }
}

私はこれをすべて間違っており、外部データ (つまりモデル) でそのようなハッシュ マップを使用するべきではありませんか、それともドットを何らかの形でエスケープできますか? たぶん、私はJavascriptのように考えすぎているのかもしれません。

4

24 に答える 24

91

MongoDB はドットを含むキーをサポートしていないため、インポートする前に JSON ファイルを前処理して削除/置換する必要があります。そうしないと、あらゆる種類の問題に備えることになります。

この問題に対する標準的な回避策はありません。最適なアプローチは、状況の詳細に大きく依存します。ただし、JSON の再構築はおそらく 1 回限りのコストになるため、キー エンコーダー/デコーダーのアプローチはできれば避けたいと思います。

于 2012-09-12T22:59:57.447 に答える
10

値の代わりにキーでハッシュを使用してみて、その値を JSON 値に格納できます。

var crypto = require("crypto");   

function md5(value) {
    return crypto.createHash('md5').update( String(value) ).digest('hex');
}

var data = {
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {}
}

var version = "9.7x";

data.models[ md5(version) ] = {
    "version": version,
    "years" : [
        2007,
        2008,
        2009,
        2010
    ]
}

後でハッシュを使用してモデルにアクセスします。

var version = "9.7x";
collection.find( { _id : ...}, function(e, data ) {
    var models = data.models[ md5(version) ];
}
于 2014-04-28T03:05:10.360 に答える
8

現在サポートされています

MongoDb 3.6以降では、フィールド名でドットドルの両方がサポートされています。以下の JIRA を参照してください: https://jira.mongodb.org/browse/JAVA-2810

Mongodb を 3.6+ にアップグレードするのが最善の方法のように思えます。

于 2019-07-19T06:24:42.180 に答える
4

キーをエスケープする必要があります。ほとんどの人は文字列を適切にエスケープする方法を知らないように思われるため、次の手順を実行します。

  1. エスケープ文字を選択します (めったに使用されない文字を選択するのが最善です)。例えば。'~'
  2. エスケープするには、最初にエスケープ文字のすべてのインスタンスを、エスケープ文字を先頭に追加したシーケンスに置き換えます (例: '~' -> '~t')。次に、エスケープする必要がある文字またはシーケンスを、エスケープ文字を先頭に追加したシーケンスに置き換えます。 . 例えば。「.」-> '~p'
  3. アンエスケープするには、最初に 2 番目のエスケープ シーケンスのすべてのインスタンスからエスケープ シーケンスを削除し (例: '~p' -> '.')、次にエスケープ文字シーケンスを単一のエスケープ文字に変換します (例: '~s' -> '~ ')

また、mongo ではキーが '$' で始まることも許可されていないため、同様のことを行う必要があります。

これを行うコードを次に示します。

// returns an escaped mongo key
exports.escape = function(key) {
  return key.replace(/~/g, '~s')
            .replace(/\./g, '~p')
            .replace(/^\$/g, '~d')
}

// returns an unescaped mongo key
exports.unescape = function(escapedKey) {
  return escapedKey.replace(/^~d/g, '$')
                   .replace(/~p/g, '.')
                   .replace(/~s/g, '~')
}
于 2016-10-28T01:36:33.483 に答える
4

MongoDBのドキュメントから「the '.' 文字はキー名のどこにも現れてはなりません」。エンコーディングスキームを考え出すか、それなしで行う必要があるようです。

于 2010-04-26T21:38:57.037 に答える
1

各オブジェクト キーに対して、JavaScript で次のエスケープを使用します。

key.replace(/\\/g, '\\\\').replace(/^\$/, '\\$').replace(/\./g, '\\_')

私が気に入っているのは、それが$最初にのみ置き換えられ、コンソールで使用するのが難しいユニコード文字を使用しないことです. _私にとっては、Unicode 文字よりもはるかに読みやすいです。$また、特殊文字 ( 、.) のセットを別のセット (Unicode)に置き換えることもありません。しかし、伝統的な で適切にエスケープし\ます。

于 2016-09-03T17:39:00.060 に答える
1

完全ではありませんが、ほとんどの状況で機能します。禁止文字を別のものに置き換えます。キーにあるため、これらの新しい文字はかなりまれです。

/** This will replace \ with ⍀, ^$ with '₴' and dots with ⋅  to make the object compatible for mongoDB insert. 
Caveats:
    1. If you have any of ⍀, ₴ or ⋅ in your original documents, they will be converted to \$.upon decoding. 
    2. Recursive structures are always an issue. A cheap way to prevent a stack overflow is by limiting the number of levels. The default max level is 10.
 */
encodeMongoObj = function(o, level = 10) {
    var build = {}, key, newKey, value
    //if (typeof level === "undefined") level = 20     // default level if not provided
    for (key in o) {
        value = o[key]
        if (typeof value === "object") value = (level > 0) ? encodeMongoObj(value, level - 1) : null     // If this is an object, recurse if we can

        newKey = key.replace(/\\/g, '⍀').replace(/^\$/, '₴').replace(/\./g, '⋅')    // replace special chars prohibited in mongo keys
        build[newKey] = value
    }
    return build
}

/** This will decode an object encoded with the above function. We assume the structure is not recursive since it should come from Mongodb */
decodeMongoObj = function(o) {
    var build = {}, key, newKey, value
    for (key in o) {
        value = o[key]
        if (typeof value === "object") value = decodeMongoObj(value)     // If this is an object, recurse
        newKey = key.replace(/⍀/g, '\\').replace(/^₴/, '$').replace(/⋅/g, '.')    // replace special chars prohibited in mongo keys
        build[newKey] = value
    }
    return build
}

ここにテストがあります:

var nastyObj = {
    "sub.obj" : {"$dollar\\backslash": "$\\.end$"}
}
nastyObj["$you.must.be.kidding"] = nastyObj     // make it recursive

var encoded = encodeMongoObj(nastyObj, 1)
console.log(encoded)
console.log( decodeMongoObj( encoded) )

および結果 - 値が変更されていないことに注意してください。

{
  sub⋅obj: {
    ₴dollar⍀backslash: "$\\.end$"
  },
  ₴you⋅must⋅be⋅kidding: {
    sub⋅obj: null,
    ₴you⋅must⋅be⋅kidding: null
  }
}
[12:02:47.691] {
  "sub.obj": {
    $dollar\\backslash: "$\\.end$"
  },
  "$you.must.be.kidding": {
    "sub.obj": {},
    "$you.must.be.kidding": {}
  }
}
于 2018-10-04T16:09:18.847 に答える
0

PHP の場合、ピリオドを HTML 値に置き換えます。それは"."

次のようにMongoDBに保存します。

  "validations" : {
     "4e25adbb1b0a55400e030000" : {
     "associate" : "true" 
    },
     "4e25adb11b0a55400e010000" : {
       "associate" : "true" 
     } 
   } 

そしてPHPコード...

  $entry = array('associate' => $associate);         
  $data = array( '$set' => array( 'validations.' . str_replace(".", `"."`, $validation) => $entry ));     
  $newstatus = $collection->update($key, $data, $options);      
于 2011-07-19T21:14:02.787 に答える
0

Lodashペアを使用すると、変更できます

{ 'connect.sid': 's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' }

の中へ

[ [ 'connect.sid',
's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' ] ]

使用して

var newObj = _.pairs(oldObj);
于 2015-10-02T09:48:20.927 に答える
0

そのまま収納してキレイに変身できます

この例は Livescript で書きました。livescript.net Web サイトを使用して評価できます

test =
  field:
    field1: 1
    field2: 2
    field3: 5
    nested:
      more: 1
      moresdafasdf: 23423
  field3: 3



get-plain = (json, parent)->
  | typeof! json is \Object => json |> obj-to-pairs |> map -> get-plain it.1, [parent,it.0].filter(-> it?).join(\.)
  | _ => key: parent, value: json

test |> get-plain |> flatten |> map (-> [it.key, it.value]) |> pairs-to-obj

それは生成します

{"field.field1":1,
 "field.field2":2,
 "field.field3":5,
 "field.nested.more":1,
 "field.nested.moresdafasdf":23423,
 "field3":3}

于 2016-09-28T10:26:10.947 に答える