Replies: 3 comments 6 replies
-
Hi Tom! Since that thread we added support for "merge" via If you don't need deduplication, i.e if the entries in your JSON array don't share sub-objects, then writing data via the GrapQL mutation route might work for you. |
Beta Was this translation helpful? Give feedback.
-
You could use json_get and to_json in unison to do this lines := {
(
FOR x in {enumerate(
# here we have individual lines as elements in a set
{'{"product":"Tomato","qty":2}', '{"product":"Pasta","qty":2}', '{"product":"Butter","qty":1}'}
)}
UNION (
INSERT OrderLine {
slno := x.0,
product := (
SELECT Product
FILTER .name = <str>(SELECT json_get(to_json(x.1),'product'))
),
qty := <int16>(SELECT json_get(to_json(x.1),'qty')
)
}
)
)
} Here is a complete example, implemeted in python (EdgeDB Alpha 7) view code
import asyncio
from typing import Optional
import ujson
import edgedb
from edgedb import AsyncIOPool
EDGEDB_INSTANCE = "a7docker"
EDGEDB_DB = "bulk"
schema = """
module default {
# sequence to keep track of order number
scalar type OrderNo extending sequence;
type User {
required property name -> str;
}
type Product {
required property name -> str;
}
type OrderLine {
property slno -> int16;
required link product -> Product;
required property qty -> int16;
}
type SaleOrder {
required property num -> OrderNo;
required link user -> User;
multi link lines -> OrderLine;
property create_date -> datetime {
default := (SELECT datetime_current());
}
}
}
"""
async def init_schema(pool: AsyncIOPool) -> None:
async with pool.acquire() as con:
await con.execute(f"""START MIGRATION TO {{ {schema} }}""")
await con.execute("""POPULATE MIGRATION""")
await con.execute("""COMMIT MIGRATION""")
async def insert_generic(
pool: AsyncIOPool, *, dbtype: str, name: str
) -> Optional[str]:
try:
if dbtype not in {"Product", "User"}:
raise Exception(f"Unsupported DB Type: {dbtype}")
async with pool.acquire() as con:
result = await con.query_one_json(
f"""SELECT (
INSERT {dbtype} {{
name := <str>$name
}}
) {{
id,
name
}}
""",
name=name)
return result
except Exception as e:
print(e)
async def insert_sale_order(pool: AsyncIOPool, request: str):
try:
request_json = ujson.loads(request)
lines = []
for line in request_json["lines"]:
lines.append(ujson.dumps(line))
lines = set(lines).__repr__()
async with pool.acquire() as con:
result = await con.query_one_json(
f"""SELECT (
INSERT SaleOrder {{
user := (SELECT User FILTER .name = <str>$name),
lines := {{
(
FOR x in {{enumerate(
{lines}
)}}
UNION (
INSERT OrderLine {{
slno := x.0,
product := (
SELECT Product
FILTER .name = <str>(
SELECT json_get(
to_json(x.1),'product'
)
)
),
qty := <int16>(
SELECT json_get(
to_json(x.1),'qty'
)
)
}}
)
)
}}
}}
) {{
id,
num,
user : {{name}},
lines : {{
slno,
product: {{name}},
qty
}}
}}
""",
name=request_json["user"])
return result
except Exception as e:
print(e)
async def main(init=True) -> None:
async with await edgedb.create_async_pool(
EDGEDB_INSTANCE, database=EDGEDB_DB
) as pool:
if init:
await init_schema(pool)
print("Initilized Schema")
await asyncio.sleep(1)
await insert_generic(pool, dbtype="User", name="Alice")
await insert_generic(pool, dbtype="Product", name="Butter")
await insert_generic(pool, dbtype="Product", name="Tomato")
await insert_generic(pool, dbtype="Product", name="Pasta Sauce")
print("Inserted Users and Products")
# assume a new order JSON was received from a client application
new_sale_order = """{
"user": "Alice",
"lines": [
{
"product": "Butter",
"qty": 1
},
{
"product": "Tomato",
"qty": 2
},
{
"product": "Pasta",
"qty": 2
}
]
}"""
result = await insert_sale_order(pool, new_sale_order)
print(f"Sale Order Create: \t{result}")
if __name__ == "__main__":
asyncio.run(main(init=True)) @elprans are there any performance penalties in the above implementation? |
Beta Was this translation helpful? Give feedback.
-
@elprans I see the beta 2 announcement today once again mentions this feature: "support for converting arbitrary strictly typed data to and from JSON via a simple cast operator" But it is positioned more as an existing feature than a new one. Has anything has changed in regard to arbitrary JSON that spans entity boundaries? |
Beta Was this translation helpful? Give feedback.
-
Hi,
I was digging into EdgeDB back in one of the alphas and learned that there was no way to throw an entire object-graph (e.g. json) into the database in one go. It was possible to do that with JSON properties, but I was looking for a way to post a graph of top-level schema objects and have EdgeDB establish all the links correctly, like Datomic does.
I raised the issue on the old Spectrum chat
https://spectrum.chat/edgedb/general/how-to-store-hierarchical-document-like-data~e1b5c7b9-e0d2-48cc-9742-95aa642a8311
Has this been addressed in the beta? The announcement mentions "casting from and to JSON" but the link leads only to docs about going to json, not from.
Thanks
Tom
Beta Was this translation helpful? Give feedback.
All reactions