MongoDB dot (.) ในชื่อคีย์


95

ดูเหมือนว่า mongo ไม่อนุญาตให้แทรกคีย์ที่มีเครื่องหมายจุด (.) หรือดอลลาร์ ($) แต่เมื่อฉันนำเข้าไฟล์ JSON ที่มีจุดอยู่โดยใช้เครื่องมือ mongoimport มันก็ใช้ได้ดี คนขับกำลังบ่นเกี่ยวกับการพยายามแทรกองค์ประกอบนั้น

นี่คือลักษณะของเอกสารในฐานข้อมูล:

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

ฉันทำสิ่งนี้ผิดทั้งหมดหรือไม่และไม่ควรใช้แฮชแมปแบบนั้นกับข้อมูลภายนอก (เช่นโมเดล) หรือฉันสามารถหลีกเลี่ยงจุดได้หรือไม่ บางทีฉันอาจจะคิดเหมือน Javascript มากเกินไป


คำตอบ:


87

MongoDB ไม่รองรับคีย์ที่มีจุดอยู่ดังนั้นคุณจะต้องประมวลผลไฟล์ JSON ของคุณล่วงหน้าเพื่อลบ / แทนที่ก่อนที่จะนำเข้าไม่เช่นนั้นคุณจะตั้งค่าตัวเองสำหรับปัญหาทุกประเภท

ไม่มีวิธีแก้ปัญหามาตรฐานสำหรับปัญหานี้แนวทางที่ดีที่สุดขึ้นอยู่กับสถานการณ์เฉพาะเจาะจงมากเกินไป แต่ฉันจะหลีกเลี่ยงวิธีการเข้ารหัส / ตัวถอดรหัสที่สำคัญหากเป็นไปได้เนื่องจากคุณจะยังคงจ่ายเงินในความไม่สะดวกนี้ต่อไปโดยที่การปรับโครงสร้าง JSON น่าจะเป็นค่าใช้จ่ายเพียงครั้งเดียว


1
ฉันไม่คิดว่าจะมีวิธีมาตรฐานวิธีที่ดีที่สุดนั้นขึ้นอยู่กับสถานการณ์เฉพาะของสถานการณ์มากเกินไป แต่ฉันจะหลีกเลี่ยงวิธีการเข้ารหัส / ตัวถอดรหัสที่สำคัญหากเป็นไปได้เนื่องจากคุณจะยังคงจ่ายเงินในความไม่สะดวกนี้ต่อไปโดยที่การปรับโครงสร้าง JSON น่าจะเป็นค่าใช้จ่ายเพียงครั้งเดียว
JohnnyHK

8
เจอสถานการณ์นี้อีกครั้ง ดูเหมือนว่าจะเกิดขึ้นไม่มากกับชื่อคีย์แอปซึ่งเราสามารถควบคุมได้และมักจะต้องค้นหา แต่ด้วยข้อมูลที่ผู้ใช้ให้มาในโครงสร้างข้อมูลที่ซ้อนกันซึ่งเราไม่สามารถควบคุมได้ แต่ (ก) ต้องการจัดเก็บใน Mongo , (b) เรารู้ว่าช่องเฉพาะใดที่อาจเกิดขึ้นใน (เช่นmodelsที่นี่) และ (c) เราไม่จำเป็นต้องค้นหาโดยใช้ชื่อคีย์ใน Mongo ดังนั้นรูปแบบที่ฉันตัดสินคือJSON.stringifyฟิลด์นี้เมื่อบันทึกและ "JSON.parse" ในการดึงข้อมูล
ต้นแบบ

16
หากคุณต้องการคุณสามารถระบุตัวเลือก {check_keys: false} เพื่อหลีกเลี่ยงปัญหานี้
Tzury Bar Yochay

5
@TzuryBarYochay OMG คุณพบ MongoDB เทียบเท่ากับทางตะวันตกเฉียงเหนือ ฉันคิดว่านี่ควรเป็นคำตอบที่ได้รับการยอมรับ
ต้นแบบ

2
@emarel db.collection_foo.update ({this: "that"}, {$ set: {a: "b"}}, {check_keys: false})
Tzury Bar Yochay

22

ตามที่ระบุไว้ในคำตอบอื่น ๆ MongoDB ไม่อนุญาต$หรือ.ตัวอักษรที่เป็นกุญแจแผนที่เนื่องจากข้อ จำกัด ในชื่อฟิลด์ อย่างไรก็ตามตามที่กล่าวไว้ในDollar Sign Operator การ หลีกเลี่ยงข้อ จำกัด นี้ไม่ได้ป้องกันไม่ให้คุณแทรกเอกสารด้วยคีย์ดังกล่าว แต่เพียงป้องกันไม่ให้คุณอัปเดตหรือสืบค้นข้อมูล

ปัญหาของการแทนที่.ด้วย[dot]หรือU+FF0E(ตามที่กล่าวไว้ที่อื่นในหน้านี้) คือจะเกิดอะไรขึ้นเมื่อผู้ใช้ต้องการจัดเก็บคีย์อย่างถูกต้อง[dot]หรือU+FF0E?

แนวทางที่ไดรเวอร์ afMorphia ของ Fantom ใช้คือการใช้ลำดับการหลบหนีแบบ Unicode ที่คล้ายกับ Java แต่ต้องแน่ใจว่าอักขระ Escape จะถูก Escape ก่อน โดยพื้นฐานแล้วการแทนที่สตริงต่อไปนี้จะทำ (*):

\  -->  \\
$  -->  \u0024
.  -->  \u002e

การแทนที่ย้อนกลับจะเกิดขึ้นเมื่อคีย์แผนที่ถูกอ่านจาก MongoDB ในภายหลัง

หรือในรหัสแฟนทอม :

Str encodeKey(Str key) {
    return key.replace("\\", "\\\\").replace("\$", "\\u0024").replace(".", "\\u002e")
}

Str decodeKey(Str key) {
    return key.replace("\\u002e", ".").replace("\\u0024", "\$").replace("\\\\", "\\")
}

ครั้งเดียวที่ผู้ใช้ต้องทราบถึง Conversion ดังกล่าวคือเมื่อสร้างคำค้นหาสำหรับคีย์ดังกล่าว

เนื่องจากเป็นเรื่องปกติที่จะจัดเก็บdotted.property.namesในฐานข้อมูลเพื่อวัตถุประสงค์ในการกำหนดค่าฉันเชื่อว่าวิธีนี้ดีกว่าในการแบนคีย์แผนที่ดังกล่าวทั้งหมด

(*) afMorphia จริงดำเนินการเต็มรูปแบบ / Unicode ที่เหมาะสมกฎการหลบหนีดังกล่าวในไวยากรณ์หลบหนี Unicode ในชวาแต่ลำดับทดแทนอธิบายงานก็เช่นกัน


ควรใช้//gเพื่อแทนที่เหตุการณ์ทั้งหมดไม่ใช่แค่ครั้งแรก นอกจากนี้การใช้การเทียบเท่าแบบเต็มความกว้างเช่นเดียวกับคำตอบของ Martin Konecny ​​ดูเหมือนจะเป็นความคิดที่ดี สุดท้ายหนึ่งแบ็กสแลชก็เพียงพอสำหรับการเข้ารหัส key.replace(/\./g, '\uff0e').replace(/\$/g, '\uff04').replace(/\\/g, '\uff3c')
cw '

1
@cw '- โค้ดอยู่ใน Java เหมือนไวยากรณ์ดังนั้นการแทนที่จะแทนที่สิ่งที่เกิดขึ้นทั้งหมดและจำเป็นต้องใช้แบ็กสแลชคู่สำหรับการหลีกเลี่ยงแบ็กสแลช และอีกครั้งคุณต้องแนะนำรูปแบบการหลบหนีเพื่อให้แน่ใจว่าทุกกรณีได้รับความคุ้มครอง U+FF04ใครบางคนที่เวลาจริงอาจต้องการที่สำคัญของ AA
Steve Eynon

2
ปรากฎว่า Mongodb รองรับจุดและดอลลาร์ในเวอร์ชันล่าสุด ดู: - stackoverflow.com/a/57106679/3515086
Abhidemon

18

เอกสาร Mongoขอแนะนำให้แทนที่ตัวอักษรที่ผิดกฎหมายเช่น$และ.เทียบเท่ากับ Unicode ของพวกเขา

ในสถานการณ์เหล่านี้คีย์จะต้องแทนที่ $ ที่สงวนไว้และ อักขระ อักขระใด ๆ ก็เพียงพอแล้ว แต่ให้พิจารณาใช้ Unicode full width equivalents: U + FF04 (เช่น“ $”) และ U + FF0E (เช่น“.”)


74
ฟังดูเหมือนเป็นสูตรสำหรับอาการปวดหัวในการแก้ไขจุดบกพร่องครั้งใหญ่บนท้องถนน
ไม่มีใคร

2
@AndrewMedico, @tamlyn - ฉันคิดว่าเอกสารมีความหมายเช่นdb.test.insert({"field\uff0ename": "test"})
P.Myer Nore

4
-1 A. นั่นเป็นความคิดที่แย่มาก - จะเกิดอะไรขึ้นถ้ามีคนพยายามใช้อักขระ Unicode เหล่านั้นเป็นกุญแจสำคัญ? จากนั้นคุณมีข้อผิดพลาดเงียบที่จะทำใครจะรู้ว่าระบบของคุณ อย่าใช้วิธีหลบหนีที่คลุมเครือแบบนั้น B. the mongo docs ไม่ได้พูดแบบนั้นอีกต่อไปอาจเป็นเพราะมีคนรู้ว่ามันเป็นความคิดที่แย่มาก
BT

7
@SergioTulentsev ฉันให้พวกเขาลบคำแนะนำ :) github.com/mongodb/docs/commit/…
BT

2
@BT: เคล็ดลับสำหรับคุณครับ :)
Sergio Tulentsev

15

เวอร์ชันเสถียรล่าสุด (v3.6.1) ของ MongoDB รองรับจุด (.) ในคีย์หรือชื่อฟิลด์แล้ว

ชื่อฟิลด์สามารถมีอักขระจุด (.) และดอลลาร์ ($) ได้แล้ว


10
แม้ว่าเซิร์ฟเวอร์จะรองรับในขณะนี้ แต่ไดรเวอร์ยังคงตรวจสอบ $ และจุดในคีย์และไม่ยอมรับ ดังนั้น Mongo จึงสนับสนุนเฉพาะจุดและอักขระดอลลาร์ในทางทฤษฎีเท่านั้น สิ่งนี้ยังใช้ไม่ได้จริง :(
JMax

บางทีคุณกำลังใช้ไคลเอนต์เก่าหรือไม่เข้ากัน ฉันใช้สิ่งนี้บนเซิร์ฟเวอร์การผลิตโดยไม่ต้องใช้เหงื่อ ฉันได้ตรวจสอบไคลเอนต์ NodeJS และ Java แล้ว
h4ck3d

ด้วย Java มันไม่ได้ผลแน่นอน! ลองใช้คำสั่งต่อไปนี้: mongoClient.getDatabase("mydb").getCollection("test").insertOne(new Document("value", new Document("key.with.dots", "value").append("$dollar", "value")));ล้มเหลวโดยใช้ mongodb-driver.3.6.3 และ MongoDB 3.6.3
JMax

1
อันที่จริงฉันเพิ่งลองตั้งค่าmongodb-4.1.1และpymongo-3.7.1. ฉันสามารถเพิ่มเอกสารที่มีกุญแจด้วย.robomongo แต่ไม่ได้จากpymongoนั้นมันทำให้เกิดความInvalidDocument: key '1.1' must not contain '.'หวังว่ามันจะได้รับการแก้ไขแล้วในตอนนี้ ...
การเรียนรู้ยุ่งเหยิง

ฉันลองใช้เซิร์ฟเวอร์ mongodb 4.0.9 และไดรเวอร์ java 3.10.2 แต่ไม่ยอมรับจุดในชื่อคีย์ มันแปลกที่เมื่อลองใช้ robomongo มันได้ผล ...
xyzt

12

วิธีแก้ปัญหาที่ฉันเพิ่งนำมาใช้ซึ่งฉันพอใจมากคือการแบ่งชื่อคีย์และค่าออกเป็นสองช่องแยกกัน ด้วยวิธีนี้ฉันสามารถทำให้ตัวละครเหมือนเดิมทุกประการและไม่ต้องกังวลกับฝันร้ายที่แยกวิเคราะห์เหล่านั้น เอกสารจะมีลักษณะดังนี้:

{
    ...
    keyName: "domain.com",
    keyValue: "unregistered",
    ...
}

คุณยังสามารถสอบถามนี้พอเรื่องง่ายเพียงแค่ด้วยการทำfindในเขตKeyName และ KeyValue

แทนที่จะเป็น:

 db.collection.find({"domain.com":"unregistered"})

ซึ่งไม่ได้ผลจริงตามที่คาดไว้คุณจะเรียกใช้:

db.collection.find({keyName:"domain.com", keyValue:"unregistered"})

และจะส่งคืนเอกสารที่คาดไว้


คุณทำได้อย่างไร? คุณช่วยฉันด้วยกรณีเดียวกันนี้ได้ไหม
profiler

ฉันเพิ่มตัวอย่างแบบสอบถาม ที่ช่วย?
Steve

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

1
ฉันชอบวิธีนี้วิธีแก้ปัญหาที่สะอาดด้วยการแฮชแบบ 1 ทางและคล้ายกับวิธีการทำงานภายใต้ประทุน
Michael Yagudaev

3
ปัญหาเกี่ยวกับการใช้แฮชเป็นกุญแจคือว่าพวกเขาจะไม่ได้รับประกันว่าจะไม่ซ้ำกันและพวกเขามักผลิตชน นอกจากนี้การคำนวณแฮชการเข้ารหัสทุกครั้งที่คุณต้องการเข้าถึงแผนที่ดูเหมือนจะไม่ใช่วิธีที่ดีที่สุดสำหรับฉัน
Steve Eynon

2
เหตุใดจึงดีกว่าการแทนที่จุดด้วยอักขระพิเศษหรือลำดับ
B Seven

การแปลงสตริงเป็น base64 นั้นดีกว่ามาก
เซน

8

ได้รับการสนับสนุนแล้ว

MongoDb 3.6เป็นต้นไปรองรับทั้งจุดและดอลลาร์ในชื่อฟิลด์ ดู JIRA ด้านล่าง: https://jira.mongodb.org/browse/JAVA-2810

การอัปเกรด Mongodb ของคุณเป็น 3.6+ เสียงเป็นวิธีที่ดีที่สุด


นี่คือคำตอบที่ดีที่สุดที่นี่ : +1
hello_abhishek

3
3.6 สามารถจัดเก็บได้ใช่ แต่ยังไม่ได้รับการสนับสนุนอาจทำให้เกิดข้อผิดพลาดของไดรเวอร์และอาจทำลายการสืบค้น / การอัปเดต: ข้อ จำกัด : "ภาษาของแบบสอบถาม MongoDB ไม่สามารถแสดงข้อความค้นหาอย่างมีความหมายได้เสมอไปบนเอกสารที่ชื่อฟิลด์มีอักขระเหล่านี้ (โปรดดูที่เซิร์ฟเวอร์ 30575) จนกว่าจะมีการเพิ่มการสนับสนุนในภาษาแบบสอบถามไม่แนะนำให้ใช้ $ และ. ในชื่อฟิลด์และไม่รองรับไดรเวอร์ MongoDB อย่างเป็นทางการ "
JeremyDouglass

4

จากเอกสาร MongoDB "the". " อักขระต้องไม่ปรากฏที่ใดก็ได้ในชื่อคีย์ " ดูเหมือนว่าคุณจะต้องใช้รูปแบบการเข้ารหัสหรือไม่ต้องทำ


4

คุณจะต้องหลบหนีกุญแจ เนื่องจากดูเหมือนว่าคนส่วนใหญ่ไม่รู้วิธีการหลีกเลี่ยงสตริงอย่างถูกต้องนี่คือขั้นตอน

  1. เลือกอักขระหลบหนี (ควรเลือกอักขระที่ไม่ค่อยได้ใช้) เช่น. '~'
  2. ในการหลบหนีอันดับแรกให้แทนที่อินสแตนซ์ทั้งหมดของอักขระหลีกด้วยลำดับบางส่วนที่นำหน้าด้วยอักขระหลีกของคุณ (เช่น '~' -> '~ t') จากนั้นแทนที่อักขระหรือลำดับที่คุณต้องการเพื่อหลีกเลี่ยงด้วยลำดับบางส่วนที่นำหน้าด้วยอักขระหลีกของคุณ . เช่น. '.' -> '~ p'
  3. ในการ unescape ขั้นแรกให้ลบลำดับการหลีกออกจากอินสแตนซ์ทั้งหมดของลำดับการหลีกเลี่ยงที่สองของคุณ (เช่น '~ 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, '~')
}

การหลบหนีนี้ยังสามารถทำลายได้หากคุณมีสตริงเช่น ". ~ p." ที่นี่สตริงหนีจะเป็น "~ p ~~ p ~ p" Unescaping จะให้ ". ~ .. " ซึ่งแตกต่างจากสตริงจริง
jvc

1
@jvc คุณพูดถูก! ฉันได้แก้ไขคำอธิบายและตัวอย่างฟังก์ชัน Escape แล้ว แจ้งให้เราทราบหากยังเสียอยู่!
BT

3

คำตอบที่ปลาย แต่ถ้าคุณใช้ฤดูใบไม้ผลิและ Mongo, MappingMongoConverterฤดูใบไม้ผลิสามารถจัดการแปลงสำหรับคุณด้วย เป็นวิธีแก้ปัญหาโดย JohnnyHK แต่จัดการโดย Spring

@Autowired
private MappingMongoConverter converter;

@PostConstruct
public void configureMongo() {
 converter.setMapKeyDotReplacement("xxx");
}

หาก Json ที่จัดเก็บของคุณคือ:

{ "axxxb" : "value" }

ผ่าน Spring (MongoClient) จะอ่านว่า:

{ "a.b" : "value" }

ต้องการ bean ชนิด 'org.springframework.data.mongodb.core.convert.MappingMongoConverter' ที่ไม่พบ
Sathya Narayan C

1

ฉันใช้การหลีกเลี่ยงต่อไปนี้ใน JavaScript สำหรับแต่ละอ็อบเจ็กต์คีย์:

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

สิ่งที่ฉันชอบเกี่ยวกับเรื่องนี้คือมันจะแทนที่$ในตอนต้นเท่านั้นและไม่ใช้อักขระ Unicode ซึ่งอาจเป็นเรื่องยากที่จะใช้ในคอนโซล _สำหรับฉันแล้วอ่านได้ง่ายกว่าตัวอักษร Unicode นอกจากนี้ยังไม่แทนที่ชุดของอักขระพิเศษ ( $, .) ด้วยอีกชุดหนึ่ง (unicode) \แต่ต้องหนีกับแบบดั้งเดิม


3
และหากมีคนใช้ _ ในคีย์ใด ๆ ของพวกเขาคุณจะได้รับข้อบกพร่อง
BT

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": {}
  }
}

1

มีวิธีที่น่าเกลียดในการสืบค้นไม่แนะนำให้ใช้ในแอปพลิเคชันแทนที่จะใช้เพื่อการดีบัก (ใช้ได้กับวัตถุฝังตัวเท่านั้น):

db.getCollection('mycollection').aggregate([
    {$match: {mymapfield: {$type: "object" }}}, //filter objects with right field type
    {$project: {mymapfield: { $objectToArray: "$mymapfield" }}}, //"unwind" map to array of {k: key, v: value} objects
    {$match: {mymapfield: {k: "my.key.with.dot", v: "myvalue"}}} //query
])

1

ดังที่ผู้ใช้รายอื่นกล่าวถึงการเข้ารหัส / ถอดรหัสสิ่งนี้อาจเป็นปัญหาได้ในอนาคตดังนั้นจึงอาจง่ายกว่าที่จะแทนที่คีย์ทั้งหมดที่มีจุด นี่คือฟังก์ชันเรียกซ้ำที่ฉันสร้างขึ้นเพื่อแทนที่ปุ่มด้วย "." เหตุการณ์:

def mongo_jsonify(dictionary):
    new_dict = {}
    if type(dictionary) is dict:
        for k, v in dictionary.items():
            new_k = k.replace('.', '-')
            if type(v) is dict:
                new_dict[new_k] = mongo_jsonify(v)
            elif type(v) is list:
                new_dict[new_k] = [mongo_jsonify(i) for i in v]
            else:
                new_dict[new_k] = dictionary[k]
        return new_dict
    else:
        return dictionary

if __name__ == '__main__':
    with open('path_to_json', "r") as input_file:
        d = json.load(input_file)
    d = mongo_jsonify(d)
    pprint(d)

คุณสามารถแก้ไขรหัสนี้เพื่อแทนที่ '$' ได้เช่นกันเนื่องจากเป็นอักขระอื่นที่ Mongo ไม่อนุญาตให้ใช้ในคีย์


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


0

คุณสามารถจัดเก็บได้ตามที่เป็นอยู่และแปลงเป็นหลังสวย

ฉันเขียนตัวอย่างนี้บน Livescript คุณสามารถใช้เว็บไซต์ livescript.net เพื่อประเมินได้

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}


0

ให้คำแนะนำของฉัน: คุณสามารถใช้ JSON.stringify เพื่อบันทึก Object / Array มีชื่อคีย์มีจุดจากนั้นแยกวิเคราะห์สตริงเป็น Object ด้วย JSON.parse เพื่อประมวลผลเมื่อได้รับข้อมูลจากฐานข้อมูล

วิธีแก้ปัญหาอื่น: ปรับโครงสร้างสคีมาของคุณเช่น:

key : {
"keyName": "a.b"
"value": [Array]
}

0

MongoDB ล่าสุดรองรับคีย์ที่มีจุด แต่ java MongoDB-driver ไม่รองรับ ดังนั้นเพื่อให้ใช้งานได้ใน Java ฉันจึงดึงโค้ดจากgithub repo ของ java-mongo-driverและทำการเปลี่ยนแปลงตามในฟังก์ชัน isValid Key ของพวกเขาสร้าง jar ใหม่จากมันโดยใช้ตอนนี้


0

แทนที่จุด ( .) หรือดอลลาร์ ( $) ด้วยอักขระอื่น ๆ ที่จะไม่ใช้ในเอกสารจริง และคืนค่าจุด ( .) หรือดอลลาร์ ( $) เมื่อดึงเอกสาร กลยุทธ์จะไม่ส่งผลต่อข้อมูลที่ผู้ใช้อ่าน

คุณสามารถเลือกตัวละครจากตัวละครทุกตัว


0

สิ่งที่แปลกคือการใช้ mongojs ฉันสามารถสร้างเอกสารด้วยจุดหากฉันตั้งค่า _id ด้วยตัวเอง แต่ฉันไม่สามารถสร้างเอกสารได้เมื่อสร้าง _id:

ทำงาน:

db.testcollection.save({"_id": "testdocument", "dot.ted.": "value"}, (err, res) => {
    console.log(err, res);
});

ไม่สำเร็จ:

db.testcollection.save({"dot.ted": "value"}, (err, res) => {
    console.log(err, res);
});

ครั้งแรกฉันคิดว่า dat การอัปเดตเอกสารด้วยปุ่มจุดก็ใช้ได้เช่นกัน แต่การระบุจุดเป็นคีย์ย่อย!

เมื่อเห็นว่า mongojs จัดการกับจุด (คีย์ย่อย) อย่างไรฉันจะตรวจสอบให้แน่ใจว่าคีย์ของฉันไม่มีจุด


0

เช่นเดียวกับสิ่งที่@JohnnyHKกล่าวถึงให้ลบเครื่องหมายวรรคตอนหรือ "." จากคีย์ของคุณเนื่องจากจะสร้างปัญหาที่ใหญ่กว่ามากเมื่อข้อมูลของคุณเริ่มสะสมเป็นชุดข้อมูลที่ใหญ่ขึ้น สิ่งนี้จะทำให้เกิดปัญหาโดยเฉพาะเมื่อคุณเรียกตัวดำเนินการรวมเช่น $ merge ซึ่งต้องมีการเข้าถึงและเปรียบเทียบคีย์ซึ่งจะทำให้เกิดข้อผิดพลาด ฉันได้เรียนรู้วิธีที่ยากแล้วโปรดอย่าทำซ้ำสำหรับผู้ที่เริ่มต้น


-2

/home/user/anaconda3/lib/python3.6/site-packages/pymongo/collection.py

พบในข้อความแสดงข้อผิดพลาด หากคุณใช้anaconda(ค้นหาไฟล์ผู้สื่อข่าวหากไม่มี) เพียงแค่เปลี่ยนค่าจากcheck_keys = Trueเป็นFalseในไฟล์ที่ระบุไว้ด้านบน มันจะได้ผล!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.