หมายเหตุ: ตัวติดตามปัญหาถูกปิดใช้งาน คุณสามารถมีส่วนร่วมได้ ดึงคำขอที่ได้รับการยอมรับ
EJDB2 เป็นเครื่องมือฐานข้อมูล JSON แบบฝังที่เผยแพร่ภายใต้ใบอนุญาต MIT
เรื่องราวของไอที-ซึมเศร้า นก และ EJDB 2.0
ลินุกซ์ | ระบบปฏิบัติการ macOS | ไอโอเอส | หุ่นยนต์ | หน้าต่าง | |
---|---|---|---|---|---|
ห้องสมุดซี | ✔️1 | ||||
โหนดJS | 3 | ||||
ชวา | ✔️2 | ||||
DartVM5 | ✔️2 | 3 | |||
พลิ้วไหว 5 | |||||
ตอบสนองพื้นเมือง 5 | 4 | ||||
สวิฟท์ 5 |
[5]
การผูกมัดเป็นสิ่งจำเป็นสำหรับผู้มีส่วนร่วมที่ไม่ได้รับการดูแล
[1]
ไม่รองรับ HTTP/Websocket #257
[2]
ไบนารีไม่ได้แจกจ่ายกับ dart pub.
คุณสามารถสร้างมันขึ้นมาได้ด้วยตนเอง
[3]
สามารถสร้างได้ แต่จำเป็นต้องเชื่อมโยงกับ windows node/dart libs
[4]
กำลังดำเนินการย้าย #273
Linux
, macOS
และ FreeBSD
มีการสนับสนุน Windows ที่จำกัดคุณใช้ EJDB หรือไม่? แจ้งให้เราทราบ!
รหัส EJDB2 ย้ายและทดสอบบน High Sierra
/ Mojave
/ Catalina
EJDB2 Swift มีผลผูกพันกับ MacOS, iOS และ Linux การผูก Swift ล้าสมัยแล้วในขณะนี้ กำลังมองหาผู้มีส่วนร่วม
brew install ejdb
ต้องใช้ cmake v3.24 หรือสูงกว่า
git clone --recurse-submodules [email protected]:Softmotions/ejdb.git
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make install
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_DEB=ON
make package
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_RPM=ON
make package
EJDB2 สามารถคอมไพล์ข้ามสำหรับ windows ได้
หมายเหตุ: API เครือข่าย HTTP/Websocket ถูกปิดใช้งานและยังไม่รองรับ
การเชื่อมโยง Nodejs/Dart ยังไม่ได้ย้ายไปยัง Windows
คู่มือการรวบรวมข้ามสำหรับ Windows
IWSTART เป็นตัวสร้างโปรเจ็กต์เริ่มต้น CMake อัตโนมัติสำหรับโปรเจ็กต์ C ที่ใช้ iowow / iwnet / ejdb2 libs
https://github.com/Softmotions/iwstart
https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_android/test
https://github.com/Softmotions/ejdb_android_todo_app
ไวยากรณ์ภาษาคิวรี EJDB (JQL) ที่ได้รับแรงบันดาลใจจากแนวคิดเบื้องหลังเชลล์ไปป์ XPath และ Unix ออกแบบมาเพื่อให้สืบค้นและอัปเดตชุดเอกสาร JSON ได้ง่าย
ตัวแยกวิเคราะห์ JQL สร้างขึ้นโดย peg/leg - ตัวสร้างตัวแยกวิเคราะห์แบบเรียกซ้ำสำหรับ C นี่คือไวยากรณ์ตัวแยกวิเคราะห์อย่างเป็นทางการ: https://github.com/Softmotions/ejdb/blob/master/src/jql/jqp.leg
สัญลักษณ์ที่ใช้ด้านล่างนี้ขึ้นอยู่กับคำอธิบายไวยากรณ์ SQL:
กฎ | คำอธิบาย |
---|---|
' ' | สตริงในเครื่องหมายคำพูดเดี่ยวหมายถึงสตริงลิเทอรัลที่ไม่มีเครื่องหมายคำพูดซึ่งเป็นส่วนหนึ่งของแบบสอบถาม |
{ a | b } | วงเล็บปีกกาล้อมรอบตัวเลือกอื่นที่จำเป็นตั้งแต่สองตัวขึ้นไป โดยคั่นด้วยแถบแนวตั้ง |
[ ] | วงเล็บเหลี่ยมระบุองค์ประกอบหรือส่วนคำสั่งเสริม องค์ประกอบหรือส่วนคำสั่งหลายรายการถูกคั่นด้วยแถบแนวตั้ง |
| | แถบแนวตั้งจะแยกองค์ประกอบไวยากรณ์ทางเลือกตั้งแต่ 2 รายการขึ้นไป |
... | วงรีบ่งบอกว่าองค์ประกอบก่อนหน้าสามารถทำซ้ำได้ การทำซ้ำไม่จำกัด เว้นแต่จะระบุไว้เป็นอย่างอื่น |
( ) | วงเล็บคือสัญลักษณ์การจัดกลุ่ม |
คำที่ไม่มีเครื่องหมายคำพูดเป็นตัวพิมพ์เล็ก | หมายถึงความหมายของบางส่วนแบบสอบถาม ตัวอย่างเช่น: placeholder_name - ชื่อของตัวยึดตำแหน่งใดๆ |
QUERY = FILTERS [ '|' APPLY ] [ '|' PROJECTIONS ] [ '|' OPTS ];
STR = { quoted_string | unquoted_string };
JSONVAL = json_value;
PLACEHOLDER = { ':'placeholder_name | '?' }
FILTERS = FILTER [{ and | or } [ not ] FILTER];
FILTER = [@collection_name]/NODE[/NODE]...;
NODE = { '*' | '**' | NODE_EXPRESSION | STR };
NODE_EXPRESSION = '[' NODE_EXPR_LEFT OP NODE_EXPR_RIGHT ']'
[{ and | or } [ not ] NODE_EXPRESSION]...;
OP = [ '!' ] { '=' | '>=' | '<=' | '>' | '<' | ~ }
| [ '!' ] { 'eq' | 'gte' | 'lte' | 'gt' | 'lt' }
| [ not ] { 'in' | 'ni' | 're' };
NODE_EXPR_LEFT = { '*' | '**' | STR | NODE_KEY_EXPR };
NODE_KEY_EXPR = '[' '*' OP NODE_EXPR_RIGHT ']'
NODE_EXPR_RIGHT = JSONVAL | STR | PLACEHOLDER
APPLY = { 'apply' | 'upsert' } { PLACEHOLDER | json_object | json_array } | 'del'
OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...
ORDERBY = { 'asc' | 'desc' } PLACEHOLDER | json_path
PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]
PROJECTION = 'all' | json_path
json_value
: ค่า JSON ที่ถูกต้อง: อ็อบเจ็กต์, อาร์เรย์, สตริง, บูล, ตัวเลขjson_path
: ตัวชี้ JSON แบบง่าย เช่น: /foo/bar
หรือ /foo/"bar with spaces"/
*
ในบริบทของ NODE
: ชื่อคีย์ออบเจ็กต์ JSON ใดๆ ที่ระดับการซ้อนเฉพาะ**
ในบริบทของ NODE
: ชื่อคีย์ออบเจ็กต์ JSON ใดๆ ที่ระดับการซ้อนโดยพลการ*
ในบริบทของ NODE_EXPR_LEFT
: ชื่อคีย์ในระดับเฉพาะ**
ในบริบทของ NODE_EXPR_LEFT
: ค่าอาร์เรย์ที่ซ้อนกันขององค์ประกอบอาร์เรย์ภายใต้คีย์เฉพาะ มาเล่นกับข้อมูลและการสืบค้นพื้นฐานบางส่วนกัน เพื่อความง่าย เราจะใช้ ejdb websocket network API ซึ่งให้ CLI แบบโต้ตอบแก่เรา งานเดียวกันนี้สามารถทำได้โดยใช้ C
API บริสุทธิ์เช่นกัน ( ejdb2.h jql.h
)
หมายเหตุ: ดูกรณีทดสอบ JQL เพื่อดูตัวอย่างเพิ่มเติม
{
"firstName" : " John " ,
"lastName" : " Doe " ,
"age" : 28 ,
"pets" : [
{ "name" : " Rexy rex " , "kind" : " dog " , "likes" : [ " bones " , " jumping " , " toys " ]},
{ "name" : " Grenny " , "kind" : " parrot " , "likes" : [ " green color " , " night " , " toys " ]}
]
}
บันทึก json เป็น sample.json
จากนั้นอัปโหลดเป็นคอลเล็กชัน family
:
# Start HTTP/WS server protected by some access token
./jbs -a ' myaccess01 '
8 Mar 16:15:58.601 INFO: HTTP/WS endpoint at localhost:9191
สามารถเข้าถึงเซิร์ฟเวอร์ได้โดยใช้จุดสิ้นสุด HTTP หรือ Websocket ข้อมูลเพิ่มเติม
curl -d ' @sample.json ' -H ' X-Access-Token:myaccess01 ' -X POST http://localhost:9191/family
เราสามารถลองใช้ไคลเอ็นต์ wscat websocket แบบโต้ตอบได้
wscat -H ' X-Access-Token:myaccess01 ' -c http://localhost:9191
connected (press CTRL+C to quit)
> k info
< k {
" version " : " 2.0.0 " ,
" file " : " db.jb " ,
" size " : 8192,
" collections " : [
{
" name " : " family " ,
" dbid " : 3,
" rnum " : 1,
" indexes " : []
}
]
}
> k get family 1
< k 1 {
" firstName " : " John " ,
" lastName " : " Doe " ,
" age " : 28,
" pets " : [
{
" name " : " Rexy rex " ,
" kind " : " dog " ,
" likes " : [
" bones " ,
" jumping " ,
" toys "
]
},
{
" name " : " Grenny " ,
" kind " : " parrot " ,
" likes " : [
" green color " ,
" night " ,
" toys "
]
}
]
}
หมายเหตุเกี่ยวกับคำนำหน้า k
ก่อนทุกคำสั่ง เป็นคีย์ที่เลือกโดยลูกค้าและกำหนดให้ระบุคำขอ websocket โดยเฉพาะ คีย์นี้จะถูกส่งกลับพร้อมกับการตอบกลับคำขอ และอนุญาตให้ลูกค้าระบุการตอบสนองนั้นสำหรับคำขอเฉพาะของเขา ข้อมูลเพิ่มเติม
คำสั่งแบบสอบถามบน websocket มีรูปแบบดังต่อไปนี้:
<key> query <collection> <query>
ดังนั้นเราจะพิจารณาเฉพาะส่วน <query>
ในเอกสารนี้
k query family /*
หรือ
k query family /**
หรือระบุชื่อคอลเลกชันในการสืบค้นอย่างชัดเจน
k @family/*
เราสามารถดำเนินการค้นหาโดยคำขอ HTTP POST
curl --data-raw '@family/[firstName = John]' -H'X-Access-Token:myaccess01' -X POST http://localhost:9191
1 {"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}]}
k @family/* | limit 10
องค์ประกอบที่ดัชนี 1
มีอยู่ในอาร์เรย์ likes
ภายในวัตถุย่อย pets
> k query family /pets/*/likes/1
< k 1 {"firstName":"John"...
องค์ประกอบที่ดัชนี 1
มีอยู่ในอาร์เรย์ likes
ในระดับการซ้อนของ likes
ใดๆ
> k query family /**/likes/1
< k 1 {"firstName":"John"...
จากจุดนี้และด้านล่าง ฉันจะละเว้นคำนำหน้าเฉพาะของ k query family
และพิจารณาเฉพาะคิวรี JQL
หากต้องการรับเอกสารโดยใช้คีย์หลัก มีตัวเลือกดังต่อไปนี้:
ใช้การเรียก API ejdb_get()
const doc = await db . get ( 'users' , 112 ) ;
ใช้โครงสร้างแบบสอบถามพิเศษ: /=:?
หรือ @collection/=:?
รับเอกสารจากการรวบรวม users
ด้วยคีย์หลัก 112
> k @users/=112
อัปเดตอาร์เรย์แท็กสำหรับเอกสารในการรวบรวม jobs
(TypeScript):
await db . createQuery ( '@jobs/ = :? | apply :? | count' )
. setNumber ( 0 , id )
. setJSON ( 1 , { tags } )
. completionPromise ( ) ;
อาร์เรย์ของคีย์หลักยังสามารถใช้สำหรับการจับคู่:
await db . createQuery ( '@jobs/ = :?| apply :? | count' )
. setJSON ( 0 , [ 23 , 1 , 2 ] )
. setJSON ( 1 , { tags } )
. completionPromise ( ) ;
ด้านล่างนี้คือชุดคำถามที่อธิบายตนเอง:
/pets/*/[name = "Rexy rex"]
/pets/*/[name eq "Rexy rex"]
/pets/*/[name = "Rexy rex" or name = Grenny]
หมายเหตุเกี่ยวกับเครื่องหมายคำพูดรอบคำที่มีการเว้นวรรค
รับเอกสารทั้งหมดที่เจ้าของ age
มากกว่า 20
และมีสัตว์เลี้ยงที่ชอบ bones
หรือ toys
/[age > 20] and /pets/*/likes/[** in ["bones", "toys"]]
ที่นี่ **
หมายถึงองค์ประกอบบางอย่างในอาร์เรย์ likes
ni
เป็นตัวดำเนินการผกผันของ in
รับเอกสารที่ bones
อยู่ในแถว likes
ค์
/pets/*/[likes ni "bones"]
เราสามารถสร้างตัวกรองที่ซับซ้อนมากขึ้นได้
( /[age <= 20] or /[lastName re "Do.*"] )
and /pets/*/likes/[** in ["bones", "toys"]]
หมายเหตุเกี่ยวกับการจัดกลุ่มวงเล็บและการจับคู่นิพจน์ทั่วไปโดยใช้ตัวดำเนินการ re
~
เป็นตัวดำเนินการจับคู่คำนำหน้า (ตั้งแต่ ejdb v2.0.53
) การจับคู่คำนำหน้าจะได้รับประโยชน์จากการใช้ดัชนี
รับเอกสารที่ /lastName
ขึ้นต้นด้วย "Do"
/[lastName ~ Do]
กรองเอกสารที่มีอาร์เรย์ likes
ซึ่งตรงกับ ["bones","jumping","toys"]
ทุกประการ
/**/[likes = ["bones","jumping","toys"]]
อัลกอริธึมการจับคู่สำหรับอาร์เรย์และแผนที่แตกต่างกัน:
{"f":"d","e":"j"}
และ {"e":"j","f":"d"}
เป็นแผนที่ที่เท่ากัน ค้นหาเอกสาร JSON ที่มีคีย์ firstName
ที่ระดับราก
/[* = "firstName"]
ฉันบริบทนี้ *
หมายถึงชื่อคีย์
คุณสามารถใช้เงื่อนไขกับชื่อคีย์และค่าคีย์พร้อมกันได้:
/[[* = "firstName"] = John]
ชื่อคีย์สามารถเป็นได้ทั้ง firstName
หรือ lastName
แต่ควรมีค่า John
ไม่ว่าในกรณีใด
/[[* in ["firstName", "lastName"]] = John]
อาจมีประโยชน์ในการสืบค้นด้วยตัวยึดตำแหน่งแบบไดนามิก (C API):
/[[* = :keyName] = :keyValue]
APPLY
ส่วนที่รับผิดชอบในการแก้ไขเนื้อหาเอกสาร
APPLY = ({'apply' | `upsert`} { PLACEHOLDER | json_object | json_array }) | 'del'
ข้อมูลจำเพาะแพตช์ JSON เป็นไปตามข้อกำหนด rfc7386
หรือ rfc6902
ที่ตามมาหลังจาก apply
คีย์เวิร์ด
มาเพิ่มวัตถุ address
ให้กับเอกสารที่ตรงกันทั้งหมด
/[firstName = John] | apply {"address":{"city":"New York", "street":""}}
หากวัตถุ JSON เป็นอาร์กิวเมนต์ของส่วน apply
จะถือเป็นการจับคู่แบบผสาน ( rfc7386
) มิฉะนั้นควรเป็นอาร์เรย์ซึ่งหมายถึงแพทช์ rfc6902
JSON ตัวยึดตำแหน่งยังรองรับโดยส่วน apply
/* | apply :?
ตั้งชื่อถนนใน address
/[firstName = John] | apply [{"op":"replace", "path":"/address/street", "value":"Fifth Avenue"}]
เพิ่มปลา Neo
ให้กับชุด pets
ของจอห์น
/[firstName = John]
| apply [{"op":"add", "path":"/pets/-", "value": {"name":"Neo", "kind":"fish"}}]
upsert
อัปเดตเอกสารที่มีอยู่โดยอาร์กิวเมนต์ json ที่กำหนดซึ่งใช้เป็นแพทช์ผสานหรือส่วนแทรกที่ให้อาร์กิวเมนต์ json เป็นอินสแตนซ์เอกสารใหม่
/[firstName = John] | upsert {"firstName": "John", "address":{"city":"New York"}}
เพิ่มค่าตัวเลขที่ระบุโดยเส้นทาง JSON ด้วยค่าที่ระบุ
ตัวอย่าง:
Document: {"foo": 1}
Patch: [{"op": "increment", "path": "/foo", "value": 2}]
Result: {"foo": 3}
เหมือนกับ add
แพตช์ JSON แต่สร้างโหนดอ็อบเจ็กต์ระดับกลางสำหรับส่วนเส้นทาง JSON ที่ขาดหายไป
ตัวอย่าง:
Document: {"foo": {"bar": 1}}
Patch: [{"op": "add_create", "path": "/foo/zaz/gaz", "value": 22}]
Result: {"foo":{"bar":1,"zaz":{"gaz":22}}}
ตัวอย่าง:
Document: {"foo": {"bar": 1}}
Patch: [{"op": "add_create", "path": "/foo/bar/gaz", "value": 22}]
Result: Error since element pointed by /foo/bar is not an object
สลับสองค่าของเอกสาร JSON โดยเริ่ม from
เส้นทาง
กฎการแลกเปลี่ยน
from
ไม่มีข้อผิดพลาดจะเพิ่มขึ้นpath
ค่านั้นจะถูกตั้งค่าตามค่า from
เส้นทาง จากนั้นวัตถุที่ชี้ from
เส้นทางจะถูกลบออกfrom
และ path
เหล่านั้นจะถูกสลับตัวอย่าง:
Document: {"foo": ["bar"], "baz": {"gaz": 11}}
Patch: [{"op": "swap", "from": "/foo/0", "path": "/baz/gaz"}]
Result: {"foo": [11], "baz": {"gaz": "bar"}}
ตัวอย่าง (การสาธิตกฎ 2):
Document: {"foo": ["bar"], "baz": {"gaz": 11}}
Patch: [{"op": "swap", "from": "/foo/0", "path": "/baz/zaz"}]
Result: {"foo":[],"baz":{"gaz":11,"zaz":"bar"}}
ใช้คำหลัก del
เพื่อลบองค์ประกอบที่ตรงกันออกจากคอลเลกชัน:
/FILTERS | del
ตัวอย่าง:
> k add family {"firstName":"Jack"}
< k 2
> k query family /[firstName re "Ja.*"]
< k 2 {"firstName":"Jack"}
# Remove selected elements from collection
> k query family /[firstName=Jack] | del
< k 2 {"firstName":"Jack"}
PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]
PROJECTION = 'all' | json_path | join_clause
การฉายภาพอนุญาตให้รับเฉพาะชุดย่อยของเอกสาร JSON ยกเว้นข้อมูลที่ไม่จำเป็น
API ตัวยึดตำแหน่งข้อความค้นหาได้รับการสนับสนุนในการฉายภาพ
มาเพิ่มเอกสารอีกหนึ่งฉบับในคอลเลกชันของเรา:
$ cat << EOF | curl -d @- -H'X-Access-Token:myaccess01' -X POST http://localhost:9191/family
{
"firstName":"Jack",
"lastName":"Parker",
"age":35,
"pets":[{"name":"Sonic", "kind":"mouse", "likes":[]}]
}
EOF
ตอนนี้สอบถามเฉพาะเจ้าของสัตว์เลี้ยงชื่อและนามสกุลจากคอลเลกชัน
> k query family /* | /{firstName,lastName}
< k 3 {"firstName":"Jack","lastName":"Parker"}
< k 1 {"firstName":"John","lastName":"Doe"}
< k
เพิ่มอาร์เรย์ pets
ให้กับทุกเอกสาร
> k query family /* | /{firstName,lastName} + /pets
< k 3 {"firstName":"Jack","lastName":"Parker","pets":[...
< k 1 {"firstName":"John","lastName":"Doe","pets":[...
ไม่รวมเฉพาะฟิลด์ pets
ในเอกสาร
> k query family /* | all - /pets
< k 3 {"firstName":"Jack","lastName":"Parker","age":35}
< k 1 {"firstName":"John","lastName":"Doe","age":28,"address":{"city":"New York","street":"Fifth Avenue"}}
< k
ที่นี่คำหลัก all
ที่ใช้แสดงถึงเอกสารทั้งหมด
รับ age
และสัตว์เลี้ยงตัวแรกในอาร์เรย์ pets
> k query family /[age > 20] | /age + /pets/0
< k 3 {"age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
< k 1 {"age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]}]}
< k
เข้าร่วมเป็นรูปธรรมการอ้างอิงถึงเอกสารไปยังวัตถุเอกสารจริงซึ่งจะแทนที่การอ้างอิงแบบแทนที่
เอกสารจะเชื่อมต่อด้วยคีย์หลักเท่านั้น
คีย์อ้างอิงควรเก็บไว้ในเอกสารผู้อ้างอิงเป็นฟิลด์ตัวเลขหรือสตริง
การรวมสามารถระบุเป็นส่วนหนึ่งของนิพจน์การฉายภาพในรูปแบบต่อไปนี้:
/.../field<collection
ที่ไหน
field
‐ ฟิลด์ JSON มีคีย์หลักของเอกสารที่เข้าร่วม<
‐ สัญลักษณ์เครื่องหมายพิเศษที่สั่งให้กลไก EJDB แทนที่ field
ด้วยเนื้อความของเอกสารที่รวมเข้าด้วยกันcollection
- ชื่อของคอลเลกชัน DB ที่มีเอกสารที่รวมอยู่เอกสารผู้อ้างอิงจะไม่ถูกแตะต้องหากไม่พบเอกสารที่เกี่ยวข้อง
นี่คือการสาธิตการรวมคอลเลกชันในเชลล์ websocket แบบโต้ตอบของเรา:
> k add artists {"name":"Leonardo Da Vinci", "years":[1452,1519]}
< k 1
> k add paintings {"name":"Mona Lisa", "year":1490, "origin":"Italy", "artist": 1}
< k 1
> k add paintings {"name":"Madonna Litta - Madonna And The Child", "year":1490, "origin":"Italy", "artist": 1}
< k 2
# Lists paintings documents
> k @paintings/*
< k 2 {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy","artist":1}
< k 1 {"name":"Mona Lisa","year":1490,"origin":"Italy","artist":1}
< k
>
# Do simple join with artists collection
> k @paintings/* | /artist<artists
< k 2 {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy",
"artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k 1 {"name":"Mona Lisa","year":1490,"origin":"Italy",
"artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k
# Strip all document fields except `name` and `artist` join
> k @paintings/* | /artist<artists + /name + /artist/*
< k 2 {"name":"Madonna Litta - Madonna And The Child","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k 1 {"name":"Mona Lisa","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k
>
# Same results as above:
> k @paintings/* | /{name, artist<artists} + /artist/*
< k 2 {"name":"Madonna Litta - Madonna And The Child","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k 1 {"name":"Mona Lisa","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k
การอ้างอิงไม่ถูกต้อง:
> k add paintings {"name":"Mona Lisa2", "year":1490, "origin":"Italy", "artist": 9999}
< k 3
> k @paintings/* | /artist<artists
< k 3 {"name":"Mona Lisa2","year":1490,"origin":"Italy","artist":9999}
< k 2 {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
< k 1 {"name":"Mona Lisa","year":1490,"origin":"Italy","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
ORDERBY = ({ 'asc' | 'desc' } PLACEHOLDER | json_path)...
ให้เพิ่มเอกสารอีกหนึ่งรายการ จากนั้นจัดเรียงเอกสารในคอลเลกชันตาม firstName
ไปหามากและเรียงลำดับ age
จากมากไปหาน้อย
> k add family {"firstName":"John", "lastName":"Ryan", "age":39}
< k 4
> k query family /* | /{firstName,lastName,age} | asc /firstName desc /age
< k 3 {"firstName":"Jack","lastName":"Parker","age":35}
< k 4 {"firstName":"John","lastName":"Ryan","age":39}
< k 1 {"firstName":"John","lastName":"Doe","age":28}
< k
asc, desc
อาจใช้ดัชนีที่กำหนดไว้สำหรับการรวบรวมเพื่อหลีกเลี่ยงขั้นตอนการแยกเอกสารที่แยกจากกัน
OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...
skip n
ข้ามบันทึกแรก n
ก่อนองค์ประกอบแรกในชุดผลลัพธ์limit n
กำหนดจำนวนเอกสารสูงสุดในชุดผลลัพธ์count
ส่งคืนเฉพาะ count
เอกสารที่ตรงกันเท่านั้น > k query family /* | count
< k 3
< k
noidx
อย่าใช้ดัชนีใด ๆ ในการดำเนินการค้นหาinverse
ตามค่าเริ่มต้น แบบสอบถามจะสแกนเอกสารจากเอกสารที่เพิ่มล่าสุดไปยังเอกสารเก่า ตัวเลือกนี้จะแปลงทิศทางการสแกนไปเป็นตรงกันข้ามและเปิดใช้งานโหมด noidx
ไม่มีผลหากแบบสอบถามมีส่วนคำสั่งการเรียงลำดับ asc/desc
สามารถสร้างดัชนีฐานข้อมูลสำหรับพาธฟิลด์ JSON ที่มีค่าตัวเลขหรือประเภทสตริงได้ ดัชนีอาจเป็นค่า unique
- ไม่อนุญาตให้มีการทำซ้ำค่าและ non unique
มีการใช้แฟล็กมาสก์บิตโหมดดัชนีต่อไปนี้ (กำหนดใน ejdb2.h
):
โหมดดัชนี | คำอธิบาย |
---|---|
0x01 EJDB_IDX_UNIQUE | ดัชนีมีเอกลักษณ์เฉพาะตัว |
0x04 EJDB_IDX_STR | ดัชนีสำหรับประเภทค่าฟิลด์ string JSON |
0x08 EJDB_IDX_I64 | ดัชนีสำหรับค่าฟิลด์จำนวนเต็มที่มีเครื่องหมาย 8 bytes width |
0x10 EJDB_IDX_F64 | ดัชนีสำหรับค่าฟิลด์จุดทศนิยมที่มีเครื่องหมาย 8 bytes width |
ตัวอย่างเช่น ดัชนีเฉพาะของประเภทสตริงจะถูกระบุโดย EJDB_IDX_UNIQUE | EJDB_IDX_STR
= 0x05
. สามารถกำหนดดัชนีสำหรับประเภทค่าเดียวเท่านั้นที่อยู่ภายใต้เส้นทางเฉพาะในเอกสาร json
ให้กำหนดดัชนีสตริงที่ไม่ซ้ำสำหรับเส้นทาง /lastName
:
> k idx family 4 /lastName
< k
การเลือกดัชนีสำหรับการสืบค้นตามกฎการศึกษาชุด
คุณสามารถตรวจสอบการใช้ดัชนีได้ตลอดเวลาโดยการออกคำสั่ง explain
ใน WS API:
> k explain family /[lastName=Doe] and /[age!=27]
< k explain [INDEX] MATCHED STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
[COLLECTOR] PLAIN
ข้อความต่อไปนี้จะถูกนำมาพิจารณาเมื่อใช้ดัชนี EJDB2:
สามารถใช้ดัชนีเดียวเท่านั้นสำหรับการดำเนินการค้นหาโดยเฉพาะ
หากแบบสอบถามประกอบด้วย or
รวมส่วนที่ระดับบนสุด หรือมีนิพจน์ negated
ที่ระดับบนสุดของนิพจน์แบบสอบถาม - ดัชนีจะไม่ถูกใช้งานเลย ดังนั้นจึงไม่มีดัชนีด้านล่าง:
/[lastName != Andy]
/[lastName = "John"] or /[lastName = Peter]
แต่จะใช้ /lastName
ดัชนีที่กำหนดไว้ข้างต้น
/[lastName = Doe]
/[lastName = Doe] and /[age = 28]
/[lastName = Doe] and not /[age = 28]
/[lastName = Doe] and /[age != 28]
ตัวดำเนินการต่อไปนี้ได้รับการสนับสนุนโดยดัชนี (ejdb 2.0.x):
eq, =
gt, >
gte, >=
lt, <
lte, <=
in
~
(การจับคู่คำนำหน้าตั้งแต่ ejdb 2.0.53) ส่วนคำสั่ง ORDERBY
อาจใช้ดัชนีเพื่อหลีกเลี่ยงการเรียงลำดับชุดผลลัพธ์
ฟิลด์อาร์เรย์ยังสามารถจัดทำดัชนีได้ เรามาสรุปกรณีการใช้งานทั่วไปกัน: การจัดทำดัชนีแท็กเอนทิตีบางส่วน:
> k add books {"name":"Mastering Ultra", "tags":["ultra", "language", "bestseller"]}
< k 1
> k add books {"name":"Learn something in 24 hours", "tags":["bestseller"]}
< k 2
> k query books /*
< k 2 {"name":"Learn something in 24 hours","tags":["bestseller"]}
< k 1 {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
< k
สร้างดัชนีสตริงสำหรับ /tags
> k idx books 4 /tags
< k
กรองหนังสือตามแท็ก bestseller
และแสดงการใช้ดัชนีในการค้นหา:
> k explain books /tags/[** in ["bestseller"]]
< k explain [INDEX] MATCHED STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
[INDEX] SELECTED STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
[COLLECTOR] PLAIN
< k 1 {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
< k 2 {"name":"Learn something in 24 hours","tags":["bestseller"]}
< k
เอกสารทั้งหมดในคอลเลกชันจะจัดเรียงตามคีย์หลักจาก descending
ดังนั้น หากคุณใช้คีย์ที่สร้างอัตโนมัติ ( ejdb_put_new
) คุณอาจมั่นใจได้ว่าเอกสารใดที่ดึงมาจากผลลัพธ์ของการสแกนแบบเต็มจะถูกเรียงลำดับตามเวลาของการแทรกตามลำดับจากมากไปน้อย เว้นแต่คุณจะไม่ใช้การเรียงลำดับแบบสอบถาม ดัชนี หรือคำหลัก inverse
ในหลายกรณี การใช้ดัชนีอาจทำให้ประสิทธิภาพการสืบค้นโดยรวมลดลง เนื่องจากคอลเลกชันดัชนีประกอบด้วยการอ้างอิงเอกสารเท่านั้น ( id
) และกลไกอาจทำการดึงเอกสารเพิ่มเติมโดยคีย์หลักเพื่อสิ้นสุดการจับคู่แบบสอบถาม ดังนั้นสำหรับคอลเลกชันที่มีขนาดไม่มากนัก การสแกนแบบเดรัจฉานอาจทำงานได้ดีกว่าการสแกนโดยใช้ดัชนี อย่างไรก็ตาม การดำเนินการจับคู่แบบตรงทั้งหมด: eq
, in
และ sorting
ตามลำดับดัชนีปกติจะได้รับประโยชน์จากดัชนีในกรณีส่วนใหญ่
หากคุณต้องการอัปเดตชุดเอกสารบางชุดด้วยการดำเนินการ apply
หรือ del
แต่ไม่ต้องการดึงเอกสารทั้งหมดอันเป็นผลมาจากการสืบค้น เพียงเพิ่มตัวแก้ไขการ count
ในการสืบค้นเพื่อกำจัดการถ่ายโอนข้อมูลที่ไม่จำเป็นและการแปลงข้อมูล json
เอ็นจิ้น EJDB มอบความสามารถในการเริ่มต้นตัวทำงานปลายทาง HTTP/Websocket แยกต่างหากซึ่งเปิดเผย API เครือข่ายสำหรับการสืบค้นและการแก้ไขข้อมูล SSL (TLS 1.2) ได้รับการสนับสนุนโดยเซิร์ฟเวอร์ jbs
วิธีที่ง่ายที่สุดในการเปิดเผยฐานข้อมูลผ่านเครือข่ายคือการใช้เซิร์ฟเวอร์ jbs
แบบสแตนด์อโลน (แน่นอนหากคุณต้องการหลีกเลี่ยงการรวม C API
)
Usage:
./jbs [options]
-v, --version Print program version.
-f, --file=<> Database file path. Default: ejdb2.db
-p, --port=NUM HTTP server port numer. Default: 9191
-l, --listen=<> Network address server will listen. Default: localhost
-k, --key=<> PEM private key file for TLS 1.2 HTTP server.
-c, --certs=<> PEM certificates file for TLS 1.2 HTTP server.
-a, --access=TOKEN|@FILE Access token to match 'X-Access-Token' HTTP header value.
-r, --access-read Allows unrestricted read-only data access.
-C, --cors Enable COSR response headers for HTTP server
-t, --trunc Cleanup/reset database file on open.
-w, --wal use the write ahead log (WAL). Used to provide data durability.
Advanced options:
-S, --sbz=NUM Max sorting buffer size. If exceeded, an overflow temp file for data will be created.
Default: 16777216, min: 1048576
-D, --dsz=NUM Initial size of buffer to process/store document on queries. Preferable average size of document.
Default: 65536, min: 16384
-T, --trylock Exit with error if database is locked by another process.
If not set, current process will wait for lock release.
จุดสิ้นสุด HTTP อาจได้รับการป้องกันโดยโทเค็นที่ระบุด้วยแฟล็ก --access
หรือโครงสร้าง C API EJDB_HTTP
หากมีการตั้งค่าโทเค็นการเข้าถึง ไคลเอ็นต์ควรจัดเตรียมส่วนหัว HTTP ของ X-Access-Token
หากจำเป็นต้องใช้โทเค็นแต่ไม่ได้ระบุโดยไคลเอ็นต์ รหัส HTTP 401
จะถูกรายงาน หากโทเค็นการเข้าถึงไม่ตรงกับโทเค็นที่เซิร์ฟเวอร์ไคลเอ็นต์ให้มาจะตอบกลับด้วยรหัส HTTP 403
เพิ่มเอกสารใหม่ให้กับ collection
200
ความสำเร็จ เนื้อความ: ตัวระบุเอกสารใหม่เป็นหมายเลข int64
แทนที่/จัดเก็บเอกสารภายใต้ id
ตัวเลขเฉพาะ
200
กับความสำเร็จ ร่างกายว่างเปล่า ลบเอกสารที่ระบุโดย id
ออกจาก collection
200
กับความสำเร็จ ร่างกายว่างเปล่า404
แก้ไขเอกสารที่ระบุโดย id
โดยข้อมูล rfc7396, rfc6902
200
กับความสำเร็จ ร่างกายว่างเปล่า ดึงเอกสารที่ระบุโดย id
จาก collection
200
กับความสำเร็จ เนื้อหา: ข้อความเอกสาร JSONcontent-type:application/json
content-length:
404
ค้นหาคอลเลกชันโดยการสืบค้นที่ให้ไว้เป็นเนื้อหา POST เนื้อความของการสืบค้นควรมีชื่อคอลเลกชันที่ใช้ในองค์ประกอบตัวกรองแรก: @collection_name/...
ส่วนหัวของคำขอ:
X-Hints
แยกคำแนะนำเพิ่มเติมให้กับกลไกฐานข้อมูล ejdb2explain
แสดงแผนการดำเนินการค้นหาก่อนองค์ประกอบแรกในชุดผลลัพธ์โดยคั่นด้วยบรรทัด --------------------
การตอบสนอง:200
กับความสำเร็จn
ในรูปแบบต่อไปนี้: rn<document id>t<document JSON body>
...
ตัวอย่าง:
curl -v --data-raw '@family/[age > 18]' -H 'X-Access-Token:myaccess01' http://localhost:9191
* Rebuilt URL to: http://localhost:9191/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9191 (#0)
> POST / HTTP/1.1
> Host: localhost:9191
> User-Agent: curl/7.58.0
> Accept: */*
> X-Access-Token:myaccess01
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 200 OK
< connection:keep-alive
< content-type:application/json
< transfer-encoding:chunked
<
4 {"firstName":"John","lastName":"Ryan","age":39}
3 {"firstName":"Jack","lastName":"Parker","age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
1 {"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}],"address":{"city":"New York","street":"Fifth Avenue"}}
* Connection #0 to host localhost left intact
curl --data-raw '@family/[lastName = "Ryan"]' -H 'X-Access-Token:myaccess01' -H 'X-Hints:explain' http://localhost:9191
[INDEX] MATCHED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
[COLLECTOR] PLAIN
--------------------
4 {"firstName":"John","lastName":"Ryan","age":39}
ดึงข้อมูลเมตา ejdb JSON และวิธีการ HTTP ที่มีอยู่ในส่วนหัว Allow
การตอบกลับ ตัวอย่าง:
curl -X OPTIONS -H 'X-Access-Token:myaccess01' http://localhost:9191/
{
"version": "2.0.0",
"file": "db.jb",
"size": 16384,
"collections": [
{
"name": "family",
"dbid": 3,
"rnum": 3,
"indexes": [
{
"ptr": "/lastName",
"mode": 4,
"idbf": 64,
"dbid": 4,
"rnum": 3
}
]
}
]
}
EJDB รองรับโปรโตคอลแบบข้อความธรรมดาผ่านโปรโตคอล HTTP websocket คุณสามารถใช้เครื่องมือ websocket CLI แบบโต้ตอบ wscat เพื่อสื่อสารกับเซิร์ฟเวอร์ด้วยมือได้
จะตอบกลับด้วยข้อความช่วยเหลือต่อไปนี้:
wscat -H 'X-Access-Token:myaccess01' -c http://localhost:9191
> ?
<
<key> info
<key> get <collection> <id>
<key> set <collection> <id> <document json>
<key> add <collection> <document json>
<key> del <collection> <id>
<key> patch <collection> <id> <patch json>
<key> idx <collection> <mode> <path>
<key> rmi <collection> <mode> <path>
<key> rmc <collection>
<key> query <collection> <query>
<key> explain <collection> <query>
<key> <query>
>
หมายเหตุเกี่ยวกับคำนำหน้า <key>
ก่อนทุกคำสั่ง เป็นคีย์ที่เลือกโดยลูกค้าและกำหนดให้ระบุคำขอ websocket โดยเฉพาะ คีย์นี้จะถูกส่งกลับพร้อมกับการตอบกลับคำขอ และอนุญาตให้ลูกค้าระบุการตอบสนองนั้นสำหรับคำขอเฉพาะของเขา
ข้อผิดพลาดจะถูกส่งกลับในรูปแบบต่อไปนี้:
<key> ERROR: <error description>
<key> info
รับข้อมูลเมตาฐานข้อมูลเป็นเอกสาร JSON
<key> get <collection> <id>
ดึงเอกสารที่ระบุโดย id
จาก collection
หากไม่พบเอกสาร IWKV_ERROR_NOTFOUND
จะถูกส่งคืน
ตัวอย่าง:
> k get family 3
< k 3 {
"firstName": "Jack",
"lastName": "Parker",
"age": 35,
"pets": [
{
"name": "Sonic",
"kind": "mouse",
"likes": []
}
]
}
หากไม่พบเอกสาร เราจะได้รับข้อผิดพลาด:
> k get family 55
< k ERROR: Key not found. (IWKV_ERROR_NOTFOUND)
>
<key> set <collection> <id> <document json>
แทนที่/เพิ่มเอกสารภายใต้ id
ตัวเลขเฉพาะ Collection
จะถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีอยู่
<key> add <collection> <document json>
เพิ่มเอกสารใหม่ลงใน <collection>
id
ใหม่ของเอกสารจะถูกสร้างขึ้นและส่งกลับเป็นการตอบกลับ `คอลเลกชัน> จะถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีอยู่
ตัวอย่าง:
> k add mycollection {"foo":"bar"}
< k 1
> k add mycollection {"foo":"bar"}
< k 2
>
<key> del <collection> <id>
ลบเอกสารที่ระบุโดย id
ออกจาก collection
หากไม่พบเอกสาร IWKV_ERROR_NOTFOUND
จะถูกส่งคืน
<key> patch <collection> <id> <patch json>
ใช้โปรแกรมแก้ไข rfc7396 หรือ rfc6902 กับเอกสารที่ระบุโดย id
หากไม่พบเอกสาร IWKV_ERROR_NOTFOUND
จะถูกส่งคืน
<key> query <collection> <query>
ดำเนินการค้นหาเอกสารใน collection
ที่ระบุ การตอบสนอง: ชุดข้อความ WS ที่มี Boidies เอกสารสิ้นสุดโดยข้อความสุดท้ายที่มีเนื้อความว่างเปล่า
> k query family /* | /firstName
< k 4 {"firstName":"John"}
< k 3 {"firstName":"Jack"}
< k 1 {"firstName":"John"}
< k
หมายเหตุเกี่ยวกับข้อความสุดท้าย: <key>
โดยไม่มีเนื้อหา
<key> explain <collection> <query>
เช่นเดียวกับ <key> query <collection> <query>
แต่ข้อความตอบกลับแรกจะนำหน้าด้วย <key> explain
และมีแผนการดำเนินการแบบสอบถาม
ตัวอย่าง:
> k explain family /* | /firstName
< k explain [INDEX] NO [COLLECTOR] PLAIN
< k 4 {"firstName":"John"}
< k 3 {"firstName":"Jack"}
< k 1 {"firstName":"John"}
< k
ดำเนินการข้อความค้นหา เนื้อหาของข้อความค้นหาควรมีชื่อคอลเลกชันที่ใช้ในองค์ประกอบตัวกรองแรก: @collection_name/...
ลักษณะการทำงานเหมือนกับ: <key> query <collection> <query>
<key> idx <collection> <mode> <path>
ตรวจสอบให้แน่ใจว่าดัชนีมี mode
ที่ระบุ (แฟล็กบิตมาสก์) สำหรับ path
json และ collection
ที่กำหนด คอลเลกชันจะถูกสร้างขึ้นหากไม่มีอยู่
โหมดดัชนี | คำอธิบาย |
---|---|
0x01 EJDB_IDX_UNIQUE | ดัชนีมีเอกลักษณ์เฉพาะตัว |
0x04 EJDB_IDX_STR | ดัชนีสำหรับประเภทค่าฟิลด์ string JSON |
0x08 EJDB_IDX_I64 | ดัชนีสำหรับค่าฟิลด์จำนวนเต็มที่มีเครื่องหมาย 8 bytes width |
0x10 EJDB_IDX_F64 | ดัชนีสำหรับค่าฟิลด์จุดทศนิยมที่มีเครื่องหมาย 8 bytes width |
ตั้งค่าดัชนีสตริงที่ไม่ซ้ำกัน (0x01 & 0x04) = 5
ในฟิลด์ /name
JSON:
k idx mycollection 5 /name
<key> rmi <collection> <mode> <path>
ลบดัชนีด้วย mode
ที่ระบุ (แฟล็กบิตมาสก์) สำหรับ path
json และ collection
ที่กำหนด ส่งคืนข้อผิดพลาดหากไม่พบดัชนีที่กำหนด
<key> rmc <collection>
ลบคอลเลกชันและข้อมูลทั้งหมดออก หมายเหตุ: หากไม่พบ collection
จะไม่มีการรายงานข้อผิดพลาด
หากคุณติดตั้ง Docker ไว้ คุณสามารถสร้างอิมเมจ Docker และรันอิมเมจนั้นในคอนเทนเนอร์ได้
cd docker
docker build -t ejdb2 .
docker run -d -p 9191:9191 --name myEJDB ejdb2 --access myAccessKey
หรือรับอิมเมจของ ejdb2
โดยตรงจาก Docker Hub
docker run -d -p 9191:9191 --name myEJDB softmotions/ejdb2 --access myAccessKey
EJDB สามารถฝังลงในแอปพลิเคชัน C/C++
ใดก็ได้ C API
บันทึกไว้ในส่วนหัวต่อไปนี้:
แอปพลิเคชันตัวอย่าง:
#include <ejdb2/ejdb2.h>
#define CHECK ( rc_ )
if (rc_) {
iwlog_ecode_error3(rc_);
return 1;
}
static iwrc documents_visitor ( EJDB_EXEC * ctx , const EJDB_DOC doc , int64_t * step ) {
// Print document to stderr
return jbl_as_json ( doc -> raw , jbl_fstream_json_printer , stderr , JBL_PRINT_PRETTY );
}
int main () {
EJDB_OPTS opts = {
. kv = {
. path = "example.db" ,
. oflags = IWKV_TRUNC
}
};
EJDB db ; // EJDB2 storage handle
int64_t id ; // Document id placeholder
JQL q = 0 ; // Query instance
JBL jbl = 0 ; // Json document
iwrc rc = ejdb_init ();
CHECK ( rc );
rc = ejdb_open ( & opts , & db );
CHECK ( rc );
// First record
rc = jbl_from_json ( & jbl , "{"name":"Bianca", "age":4}" );
RCGO ( rc , finish );
rc = ejdb_put_new ( db , "parrots" , jbl , & id );
RCGO ( rc , finish );
jbl_destroy ( & jbl );
// Second record
rc = jbl_from_json ( & jbl , "{"name":"Darko", "age":8}" );
RCGO ( rc , finish );
rc = ejdb_put_new ( db , "parrots" , jbl , & id );
RCGO ( rc , finish );
jbl_destroy ( & jbl );
// Now execute a query
rc = jql_create ( & q , "parrots" , "/[age > :age]" );
RCGO ( rc , finish );
EJDB_EXEC ux = {
. db = db ,
. q = q ,
. visitor = documents_visitor
};
// Set query placeholder value.
// Actual query will be /[age > 3]
rc = jql_set_i64 ( q , "age" , 0 , 3 );
RCGO ( rc , finish );
// Now execute the query
rc = ejdb_exec ( & ux );
finish:
jql_destroy ( & q );
jbl_destroy ( & jbl );
ejdb_close ( & db );
CHECK ( rc );
return 0 ;
}
คอมไพล์และรัน:
gcc -std=gnu11 -Wall -pedantic -c -o example1.o example1.c
gcc -o example1 example1.o -lejdb2
./example1
{
"name": "Darko",
"age": 8
}{
"name": "Bianca",
"age": 4
}
MIT License
Copyright (c) 2012-2024 Softmotions Ltd <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.