[{"data":1,"prerenderedAt":3523},["ShallowReactive",2],{"navigation_docs":3,"-essentials-relations":106,"-essentials-relations-surround":3518},[4,26,57,83],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting Started","i-lucide-rocket","/getting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","/getting-started/introduction","1.getting-started/1.introduction","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/getting-started/installation","1.getting-started/2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","/getting-started/quick-start","1.getting-started/3.quick-start","i-lucide-play",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Core Concepts","i-lucide-book-open","/essentials","2.essentials",[32,37,42,47,52],{"title":33,"path":34,"stem":35,"icon":36},"Models","/essentials/models","2.essentials/1.models","i-lucide-box",{"title":38,"path":39,"stem":40,"icon":41},"Collections","/essentials/collections","2.essentials/2.collections","i-lucide-folder",{"title":43,"path":44,"stem":45,"icon":46},"Views","/essentials/views","2.essentials/3.views","i-lucide-table",{"title":48,"path":49,"stem":50,"icon":51},"Schema Evolution","/essentials/schema-evolution","2.essentials/4.schema-evolution","i-lucide-git-branch",{"title":53,"path":54,"stem":55,"icon":56},"Relations","/essentials/relations","2.essentials/5.relations","i-lucide-link",{"title":58,"icon":59,"path":60,"stem":61,"children":62,"page":25},"Advanced","i-lucide-settings","/advanced","3.advanced",[63,68,73,78],{"title":64,"path":65,"stem":66,"icon":67},"Time-Series","/advanced/time-series","3.advanced/1.time-series","i-lucide-chart-line",{"title":69,"path":70,"stem":71,"icon":72},"Async Support","/advanced/async","3.advanced/2.async","i-lucide-zap",{"title":74,"path":75,"stem":76,"icon":77},"PostgreSQL","/advanced/postgresql","3.advanced/3.postgresql","i-lucide-database",{"title":79,"path":80,"stem":81,"icon":82},"Performance Guide","/advanced/performance","3.advanced/4.performance","i-lucide-gauge",{"title":84,"icon":85,"path":86,"stem":87,"children":88,"page":25},"API Reference","i-lucide-file-code","/api","4.api",[89,94,98,101],{"title":90,"path":91,"stem":92,"icon":93},"Engine","/api/engine","4.api/1.engine","i-lucide-cog",{"title":95,"path":96,"stem":97,"icon":41},"Collection","/api/collection","4.api/2.collection",{"title":33,"path":99,"stem":100,"icon":36},"/api/models","4.api/3.models",{"title":102,"path":103,"stem":104,"icon":105},"Exceptions","/api/exceptions","4.api/4.exceptions","i-lucide-alert-triangle",{"id":107,"title":53,"body":108,"description":3511,"extension":3512,"links":3513,"meta":3514,"navigation":3515,"path":54,"seo":3516,"stem":55,"__hash__":3517},"docs/2.essentials/5.relations.md",{"type":109,"value":110,"toc":3483},"minimark",[111,124,131,134,142,197,759,763,803,1186,1190,1228,1235,1239,1242,1401,1419,1422,1487,1506,1512,1516,1519,1523,1528,1769,1775,1778,1877,1885,1895,1899,1905,1908,2018,2025,2031,2034,2275,2279,2289,2349,2352,2369,2372,2456,2472,2475,2479,2485,2626,2630,2633,2764,2767,2926,2940,2957,2961,2974,3053,3056,3122,3126,3148,3308,3317,3321,3330,3472,3479],[112,113,114,115,119,120,123],"p",{},"CentauroDB supports one-to-many relationships between models. A child declares a ",[116,117,118],"code",{},"parent_ref"," field that stores the parent's ",[116,121,122],{},"row.id",", and the collection provides helpers to link, write, and query children. This guide walks through the entire workflow with a practical example.",[125,126,128,130],"h2",{"id":127},"parent_ref-vs-nested-models",[116,129,118],{}," vs nested models",[112,132,133],{},"CentauroDB gives you two ways to represent related data. Choosing the right one depends on whether the child data has an independent lifecycle.",[135,136,138,139,141],"h3",{"id":137},"use-parent_ref-when","Use ",[116,140,118],{}," when:",[143,144,145,154,169,176,183],"ul",{},[146,147,148,149,153],"li",{},"The child entity has its ",[150,151,152],"strong",{},"own lifecycle"," — it can be created, updated, queried, or deleted independently of the parent",[146,155,156,157,160,161,164,165,168],{},"You need to ",[150,158,159],{},"query children without loading the parent"," (via ",[116,162,163],{},"children_of"," or ",[116,166,167],{},"read_objects"," with a filter)",[146,170,171,172,175],{},"The relationship is one-to-many and the child set can ",[150,173,174],{},"grow over time"," (e.g. Server → Logs, Project → Tasks)",[146,177,178,179,182],{},"You want the child ",[150,180,181],{},"visible in views"," with its own indexed columns",[146,184,185,186,189,190,193,194],{},"You want to ",[150,187,188],{},"keep the history of changes"," — each child is its own row with its own ",[116,191,192],{},"write_time"," and ",[116,195,196],{},"edit_time",[198,199,204],"pre",{"className":200,"code":201,"language":202,"meta":203,"style":203},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","from centaurodb import Engine, Collection, CentauroModel, parent_ref\n\nclass Server(CentauroModel):\n    __centauro_name__ = \"Server\"\n    hostname: str = \"\"\n\nclass Log(CentauroModel):\n    __centauro_name__ = \"Log\"\n    server: int | None = parent_ref(Server)\n    level: str = \"info\"\n    message: str = \"\"\n\nengine = Engine()\ncoll = Collection(engine, \"infra\")\n\n# Write the parent\nsrv = Server(hostname=\"pegasus-01\")\ncoll.write_object(srv)\n\n# Each log is written independently — its own row, its own timestamp\ncoll.write_child(Log(level=\"info\", message=\"Started\"), parent=srv)\ncoll.write_child(Log(level=\"error\", message=\"Disk full\"), parent=srv)\ncoll.write_child(Log(level=\"info\", message=\"Recovered\"), parent=srv)\n\n# Query logs independently — no need to load the server\nerrors = coll.read_objects(\n    Log.fields.server == srv.row.id,\n    Log.fields.level == \"error\",\n)\n","python","",[116,205,206,242,249,269,288,306,311,325,339,369,388,402,407,420,447,452,459,486,505,510,516,569,618,666,671,677,695,731,754],{"__ignoreMap":203},[207,208,211,215,219,222,225,229,232,234,237,239],"span",{"class":209,"line":210},"line",1,[207,212,214],{"class":213},"s7zQu","from",[207,216,218],{"class":217},"sTEyZ"," centaurodb ",[207,220,221],{"class":213},"import",[207,223,224],{"class":217}," Engine",[207,226,228],{"class":227},"sMK4o",",",[207,230,231],{"class":217}," Collection",[207,233,228],{"class":227},[207,235,236],{"class":217}," CentauroModel",[207,238,228],{"class":227},[207,240,241],{"class":217}," parent_ref\n",[207,243,245],{"class":209,"line":244},2,[207,246,248],{"emptyLinePlaceholder":247},true,"\n",[207,250,252,256,260,263,266],{"class":209,"line":251},3,[207,253,255],{"class":254},"spNyl","class",[207,257,259],{"class":258},"sBMFI"," Server",[207,261,262],{"class":227},"(",[207,264,265],{"class":258},"CentauroModel",[207,267,268],{"class":227},"):\n",[207,270,272,275,278,281,285],{"class":209,"line":271},4,[207,273,274],{"class":217},"    __centauro_name__ ",[207,276,277],{"class":227},"=",[207,279,280],{"class":227}," \"",[207,282,284],{"class":283},"sfazB","Server",[207,286,287],{"class":227},"\"\n",[207,289,291,294,297,300,303],{"class":209,"line":290},5,[207,292,293],{"class":217},"    hostname",[207,295,296],{"class":227},":",[207,298,299],{"class":258}," str",[207,301,302],{"class":227}," =",[207,304,305],{"class":227}," \"\"\n",[207,307,309],{"class":209,"line":308},6,[207,310,248],{"emptyLinePlaceholder":247},[207,312,314,316,319,321,323],{"class":209,"line":313},7,[207,315,255],{"class":254},[207,317,318],{"class":258}," Log",[207,320,262],{"class":227},[207,322,265],{"class":258},[207,324,268],{"class":227},[207,326,328,330,332,334,337],{"class":209,"line":327},8,[207,329,274],{"class":217},[207,331,277],{"class":227},[207,333,280],{"class":227},[207,335,336],{"class":283},"Log",[207,338,287],{"class":227},[207,340,342,345,347,350,353,356,358,362,364,366],{"class":209,"line":341},9,[207,343,344],{"class":217},"    server",[207,346,296],{"class":227},[207,348,349],{"class":258}," int",[207,351,352],{"class":227}," |",[207,354,355],{"class":227}," None",[207,357,302],{"class":227},[207,359,361],{"class":360},"s2Zo4"," parent_ref",[207,363,262],{"class":227},[207,365,284],{"class":360},[207,367,368],{"class":227},")\n",[207,370,372,375,377,379,381,383,386],{"class":209,"line":371},10,[207,373,374],{"class":217},"    level",[207,376,296],{"class":227},[207,378,299],{"class":258},[207,380,302],{"class":227},[207,382,280],{"class":227},[207,384,385],{"class":283},"info",[207,387,287],{"class":227},[207,389,391,394,396,398,400],{"class":209,"line":390},11,[207,392,393],{"class":217},"    message",[207,395,296],{"class":227},[207,397,299],{"class":258},[207,399,302],{"class":227},[207,401,305],{"class":227},[207,403,405],{"class":209,"line":404},12,[207,406,248],{"emptyLinePlaceholder":247},[207,408,410,413,415,417],{"class":209,"line":409},13,[207,411,412],{"class":217},"engine ",[207,414,277],{"class":227},[207,416,224],{"class":360},[207,418,419],{"class":227},"()\n",[207,421,423,426,428,430,432,435,437,439,442,445],{"class":209,"line":422},14,[207,424,425],{"class":217},"coll ",[207,427,277],{"class":227},[207,429,231],{"class":360},[207,431,262],{"class":227},[207,433,434],{"class":360},"engine",[207,436,228],{"class":227},[207,438,280],{"class":227},[207,440,441],{"class":283},"infra",[207,443,444],{"class":227},"\"",[207,446,368],{"class":227},[207,448,450],{"class":209,"line":449},15,[207,451,248],{"emptyLinePlaceholder":247},[207,453,455],{"class":209,"line":454},16,[207,456,458],{"class":457},"sHwdD","# Write the parent\n",[207,460,462,465,467,469,471,475,477,479,482,484],{"class":209,"line":461},17,[207,463,464],{"class":217},"srv ",[207,466,277],{"class":227},[207,468,259],{"class":360},[207,470,262],{"class":227},[207,472,474],{"class":473},"sHdIc","hostname",[207,476,277],{"class":227},[207,478,444],{"class":227},[207,480,481],{"class":283},"pegasus-01",[207,483,444],{"class":227},[207,485,368],{"class":227},[207,487,489,492,495,498,500,503],{"class":209,"line":488},18,[207,490,491],{"class":217},"coll",[207,493,494],{"class":227},".",[207,496,497],{"class":360},"write_object",[207,499,262],{"class":227},[207,501,502],{"class":360},"srv",[207,504,368],{"class":227},[207,506,508],{"class":209,"line":507},19,[207,509,248],{"emptyLinePlaceholder":247},[207,511,513],{"class":209,"line":512},20,[207,514,515],{"class":457},"# Each log is written independently — its own row, its own timestamp\n",[207,517,519,521,523,526,528,530,532,535,537,539,541,543,545,548,550,552,555,557,560,563,565,567],{"class":209,"line":518},21,[207,520,491],{"class":217},[207,522,494],{"class":227},[207,524,525],{"class":360},"write_child",[207,527,262],{"class":227},[207,529,336],{"class":360},[207,531,262],{"class":227},[207,533,534],{"class":473},"level",[207,536,277],{"class":227},[207,538,444],{"class":227},[207,540,385],{"class":283},[207,542,444],{"class":227},[207,544,228],{"class":227},[207,546,547],{"class":473}," message",[207,549,277],{"class":227},[207,551,444],{"class":227},[207,553,554],{"class":283},"Started",[207,556,444],{"class":227},[207,558,559],{"class":227},"),",[207,561,562],{"class":473}," parent",[207,564,277],{"class":227},[207,566,502],{"class":360},[207,568,368],{"class":227},[207,570,572,574,576,578,580,582,584,586,588,590,593,595,597,599,601,603,606,608,610,612,614,616],{"class":209,"line":571},22,[207,573,491],{"class":217},[207,575,494],{"class":227},[207,577,525],{"class":360},[207,579,262],{"class":227},[207,581,336],{"class":360},[207,583,262],{"class":227},[207,585,534],{"class":473},[207,587,277],{"class":227},[207,589,444],{"class":227},[207,591,592],{"class":283},"error",[207,594,444],{"class":227},[207,596,228],{"class":227},[207,598,547],{"class":473},[207,600,277],{"class":227},[207,602,444],{"class":227},[207,604,605],{"class":283},"Disk full",[207,607,444],{"class":227},[207,609,559],{"class":227},[207,611,562],{"class":473},[207,613,277],{"class":227},[207,615,502],{"class":360},[207,617,368],{"class":227},[207,619,621,623,625,627,629,631,633,635,637,639,641,643,645,647,649,651,654,656,658,660,662,664],{"class":209,"line":620},23,[207,622,491],{"class":217},[207,624,494],{"class":227},[207,626,525],{"class":360},[207,628,262],{"class":227},[207,630,336],{"class":360},[207,632,262],{"class":227},[207,634,534],{"class":473},[207,636,277],{"class":227},[207,638,444],{"class":227},[207,640,385],{"class":283},[207,642,444],{"class":227},[207,644,228],{"class":227},[207,646,547],{"class":473},[207,648,277],{"class":227},[207,650,444],{"class":227},[207,652,653],{"class":283},"Recovered",[207,655,444],{"class":227},[207,657,559],{"class":227},[207,659,562],{"class":473},[207,661,277],{"class":227},[207,663,502],{"class":360},[207,665,368],{"class":227},[207,667,669],{"class":209,"line":668},24,[207,670,248],{"emptyLinePlaceholder":247},[207,672,674],{"class":209,"line":673},25,[207,675,676],{"class":457},"# Query logs independently — no need to load the server\n",[207,678,680,683,685,688,690,692],{"class":209,"line":679},26,[207,681,682],{"class":217},"errors ",[207,684,277],{"class":227},[207,686,687],{"class":217}," coll",[207,689,494],{"class":227},[207,691,167],{"class":360},[207,693,694],{"class":227},"(\n",[207,696,698,701,703,707,709,712,715,718,720,723,725,728],{"class":209,"line":697},27,[207,699,700],{"class":360},"    Log",[207,702,494],{"class":227},[207,704,706],{"class":705},"swJcz","fields",[207,708,494],{"class":227},[207,710,711],{"class":705},"server",[207,713,714],{"class":227}," ==",[207,716,717],{"class":360}," srv",[207,719,494],{"class":227},[207,721,722],{"class":705},"row",[207,724,494],{"class":227},[207,726,727],{"class":705},"id",[207,729,730],{"class":227},",\n",[207,732,734,736,738,740,742,744,746,748,750,752],{"class":209,"line":733},28,[207,735,700],{"class":360},[207,737,494],{"class":227},[207,739,706],{"class":705},[207,741,494],{"class":227},[207,743,534],{"class":705},[207,745,714],{"class":227},[207,747,280],{"class":227},[207,749,592],{"class":283},[207,751,444],{"class":227},[207,753,730],{"class":227},[207,755,757],{"class":209,"line":756},29,[207,758,368],{"class":227},[135,760,762],{"id":761},"use-nested-pydantic-models-when","Use nested Pydantic models when:",[143,764,765,772,779,786,797],{},[146,766,767,768,771],{},"The nested data has ",[150,769,770],{},"no meaning outside the parent"," — it is always loaded, saved, and deleted together with it",[146,773,774,775,778],{},"You ",[150,776,777],{},"never need to query or filter"," on the nested objects independently (they live inside the parent's JSON blob)",[146,780,781,782,785],{},"The data is ",[150,783,784],{},"bounded and small"," (e.g. user preferences, a config object inside a server)",[146,787,788,789,792,793,796],{},"You want ",[150,790,791],{},"atomic reads/writes"," — one ",[116,794,795],{},"read_object"," call returns the complete aggregate",[146,798,774,799,802],{},[150,800,801],{},"don't need change history"," — updating the parent overwrites the nested data in place",[198,804,806],{"className":200,"code":805,"language":202,"meta":203,"style":203},"from pydantic import BaseModel\nfrom centaurodb import Engine, Collection, CentauroModel\n\nclass Preferences(BaseModel):\n    theme: str = \"dark\"\n    language: str = \"en\"\n    notifications: bool = True\n\nclass User(CentauroModel):\n    __centauro_name__ = \"User\"\n    name: str = \"\"\n    prefs: Preferences = Preferences()   # embedded — no separate table\n    tags: list[str] = []                 # simple embedded list\n\nengine = Engine()\ncoll = Collection(engine, \"app\")\n\n# Write the user — preferences are stored inside the same JSON blob\nuser = User(name=\"Chiron\", prefs=Preferences(theme=\"light\"))\ncoll.write_object(user)\n\n# Update preferences by mutating the parent and updating\nuser.prefs.language = \"el\"\nuser.tags.append(\"admin\")\ncoll.update_object(user)\n# Previous preferences are overwritten — no history kept\n",[116,807,808,820,839,843,857,875,893,908,912,925,938,951,971,998,1002,1012,1035,1039,1044,1094,1109,1113,1118,1141,1166,1181],{"__ignoreMap":203},[207,809,810,812,815,817],{"class":209,"line":210},[207,811,214],{"class":213},[207,813,814],{"class":217}," pydantic ",[207,816,221],{"class":213},[207,818,819],{"class":217}," BaseModel\n",[207,821,822,824,826,828,830,832,834,836],{"class":209,"line":244},[207,823,214],{"class":213},[207,825,218],{"class":217},[207,827,221],{"class":213},[207,829,224],{"class":217},[207,831,228],{"class":227},[207,833,231],{"class":217},[207,835,228],{"class":227},[207,837,838],{"class":217}," CentauroModel\n",[207,840,841],{"class":209,"line":251},[207,842,248],{"emptyLinePlaceholder":247},[207,844,845,847,850,852,855],{"class":209,"line":271},[207,846,255],{"class":254},[207,848,849],{"class":258}," Preferences",[207,851,262],{"class":227},[207,853,854],{"class":258},"BaseModel",[207,856,268],{"class":227},[207,858,859,862,864,866,868,870,873],{"class":209,"line":290},[207,860,861],{"class":217},"    theme",[207,863,296],{"class":227},[207,865,299],{"class":258},[207,867,302],{"class":227},[207,869,280],{"class":227},[207,871,872],{"class":283},"dark",[207,874,287],{"class":227},[207,876,877,880,882,884,886,888,891],{"class":209,"line":308},[207,878,879],{"class":217},"    language",[207,881,296],{"class":227},[207,883,299],{"class":258},[207,885,302],{"class":227},[207,887,280],{"class":227},[207,889,890],{"class":283},"en",[207,892,287],{"class":227},[207,894,895,898,900,903,905],{"class":209,"line":313},[207,896,897],{"class":217},"    notifications",[207,899,296],{"class":227},[207,901,902],{"class":258}," bool",[207,904,302],{"class":227},[207,906,907],{"class":227}," True\n",[207,909,910],{"class":209,"line":327},[207,911,248],{"emptyLinePlaceholder":247},[207,913,914,916,919,921,923],{"class":209,"line":341},[207,915,255],{"class":254},[207,917,918],{"class":258}," User",[207,920,262],{"class":227},[207,922,265],{"class":258},[207,924,268],{"class":227},[207,926,927,929,931,933,936],{"class":209,"line":371},[207,928,274],{"class":217},[207,930,277],{"class":227},[207,932,280],{"class":227},[207,934,935],{"class":283},"User",[207,937,287],{"class":227},[207,939,940,943,945,947,949],{"class":209,"line":390},[207,941,942],{"class":217},"    name",[207,944,296],{"class":227},[207,946,299],{"class":258},[207,948,302],{"class":227},[207,950,305],{"class":227},[207,952,953,956,958,961,963,965,968],{"class":209,"line":404},[207,954,955],{"class":217},"    prefs",[207,957,296],{"class":227},[207,959,960],{"class":217}," Preferences ",[207,962,277],{"class":227},[207,964,849],{"class":360},[207,966,967],{"class":227},"()",[207,969,970],{"class":457},"   # embedded — no separate table\n",[207,972,973,976,978,981,984,987,990,992,995],{"class":209,"line":409},[207,974,975],{"class":217},"    tags",[207,977,296],{"class":227},[207,979,980],{"class":217}," list",[207,982,983],{"class":227},"[",[207,985,986],{"class":258},"str",[207,988,989],{"class":227},"]",[207,991,302],{"class":227},[207,993,994],{"class":227}," []",[207,996,997],{"class":457},"                 # simple embedded list\n",[207,999,1000],{"class":209,"line":422},[207,1001,248],{"emptyLinePlaceholder":247},[207,1003,1004,1006,1008,1010],{"class":209,"line":449},[207,1005,412],{"class":217},[207,1007,277],{"class":227},[207,1009,224],{"class":360},[207,1011,419],{"class":227},[207,1013,1014,1016,1018,1020,1022,1024,1026,1028,1031,1033],{"class":209,"line":454},[207,1015,425],{"class":217},[207,1017,277],{"class":227},[207,1019,231],{"class":360},[207,1021,262],{"class":227},[207,1023,434],{"class":360},[207,1025,228],{"class":227},[207,1027,280],{"class":227},[207,1029,1030],{"class":283},"app",[207,1032,444],{"class":227},[207,1034,368],{"class":227},[207,1036,1037],{"class":209,"line":461},[207,1038,248],{"emptyLinePlaceholder":247},[207,1040,1041],{"class":209,"line":488},[207,1042,1043],{"class":457},"# Write the user — preferences are stored inside the same JSON blob\n",[207,1045,1046,1049,1051,1053,1055,1058,1060,1062,1065,1067,1069,1072,1074,1077,1079,1082,1084,1086,1089,1091],{"class":209,"line":507},[207,1047,1048],{"class":217},"user ",[207,1050,277],{"class":227},[207,1052,918],{"class":360},[207,1054,262],{"class":227},[207,1056,1057],{"class":473},"name",[207,1059,277],{"class":227},[207,1061,444],{"class":227},[207,1063,1064],{"class":283},"Chiron",[207,1066,444],{"class":227},[207,1068,228],{"class":227},[207,1070,1071],{"class":473}," prefs",[207,1073,277],{"class":227},[207,1075,1076],{"class":360},"Preferences",[207,1078,262],{"class":227},[207,1080,1081],{"class":473},"theme",[207,1083,277],{"class":227},[207,1085,444],{"class":227},[207,1087,1088],{"class":283},"light",[207,1090,444],{"class":227},[207,1092,1093],{"class":227},"))\n",[207,1095,1096,1098,1100,1102,1104,1107],{"class":209,"line":512},[207,1097,491],{"class":217},[207,1099,494],{"class":227},[207,1101,497],{"class":360},[207,1103,262],{"class":227},[207,1105,1106],{"class":360},"user",[207,1108,368],{"class":227},[207,1110,1111],{"class":209,"line":518},[207,1112,248],{"emptyLinePlaceholder":247},[207,1114,1115],{"class":209,"line":571},[207,1116,1117],{"class":457},"# Update preferences by mutating the parent and updating\n",[207,1119,1120,1122,1124,1127,1129,1132,1134,1136,1139],{"class":209,"line":620},[207,1121,1106],{"class":217},[207,1123,494],{"class":227},[207,1125,1126],{"class":705},"prefs",[207,1128,494],{"class":227},[207,1130,1131],{"class":705},"language",[207,1133,302],{"class":227},[207,1135,280],{"class":227},[207,1137,1138],{"class":283},"el",[207,1140,287],{"class":227},[207,1142,1143,1145,1147,1150,1152,1155,1157,1159,1162,1164],{"class":209,"line":668},[207,1144,1106],{"class":217},[207,1146,494],{"class":227},[207,1148,1149],{"class":705},"tags",[207,1151,494],{"class":227},[207,1153,1154],{"class":360},"append",[207,1156,262],{"class":227},[207,1158,444],{"class":227},[207,1160,1161],{"class":283},"admin",[207,1163,444],{"class":227},[207,1165,368],{"class":227},[207,1167,1168,1170,1172,1175,1177,1179],{"class":209,"line":673},[207,1169,491],{"class":217},[207,1171,494],{"class":227},[207,1173,1174],{"class":360},"update_object",[207,1176,262],{"class":227},[207,1178,1106],{"class":360},[207,1180,368],{"class":227},[207,1182,1183],{"class":209,"line":679},[207,1184,1185],{"class":457},"# Previous preferences are overwritten — no history kept\n",[135,1187,1189],{"id":1188},"rules-of-thumb","Rules of thumb",[143,1191,1192,1201,1208,1218],{},[146,1193,1194,1195,1198,1199],{},"If you'd put a ",[150,1196,1197],{},"foreign key"," in SQL (Server → Logs) → use ",[116,1200,118],{},[146,1202,1203,1204,1207],{},"If you'd ",[150,1205,1206],{},"embed a sub-document"," in MongoDB (User → Preferences) → use a nested model",[146,1209,1210,1211,1214,1215,1217],{},"If you need a ",[150,1212,1213],{},"trail of changes"," over time → use ",[116,1216,118],{}," (each child has its own timestamps)",[146,1219,1220,1221,1224,1225,1227],{},"If you're unsure, ",[150,1222,1223],{},"start nested"," — it's simpler. Promote to ",[116,1226,118],{}," only when you need independent queries or the child set becomes large",[1229,1230,1231,1232,1234],"tip",{},"Nested models are stored inside the parent's JSON blob, so they don't appear in views or indexes. If you later need to query or filter on nested data, or keep a history of changes, promote it to a ",[116,1233,118],{}," relationship.",[125,1236,1238],{"id":1237},"defining-a-relationship","Defining a relationship",[112,1240,1241],{},"Imagine you're building a quest tracker. Quests have many tasks:",[198,1243,1245],{"className":200,"code":1244,"language":202,"meta":203,"style":203},"from centaurodb import CentauroModel, parent_ref\n\nclass Quest(CentauroModel):\n    __centauro_name__ = \"Quest\"\n    name: str = \"\"\n    status: str = \"active\"\n\nclass Task(CentauroModel):\n    __centauro_name__ = \"Task\"\n    quest: int | None = parent_ref(Quest)\n    title: str = \"\"\n    done: bool = False\n",[116,1246,1247,1261,1265,1278,1291,1303,1321,1325,1338,1351,1374,1387],{"__ignoreMap":203},[207,1248,1249,1251,1253,1255,1257,1259],{"class":209,"line":210},[207,1250,214],{"class":213},[207,1252,218],{"class":217},[207,1254,221],{"class":213},[207,1256,236],{"class":217},[207,1258,228],{"class":227},[207,1260,241],{"class":217},[207,1262,1263],{"class":209,"line":244},[207,1264,248],{"emptyLinePlaceholder":247},[207,1266,1267,1269,1272,1274,1276],{"class":209,"line":251},[207,1268,255],{"class":254},[207,1270,1271],{"class":258}," Quest",[207,1273,262],{"class":227},[207,1275,265],{"class":258},[207,1277,268],{"class":227},[207,1279,1280,1282,1284,1286,1289],{"class":209,"line":271},[207,1281,274],{"class":217},[207,1283,277],{"class":227},[207,1285,280],{"class":227},[207,1287,1288],{"class":283},"Quest",[207,1290,287],{"class":227},[207,1292,1293,1295,1297,1299,1301],{"class":209,"line":290},[207,1294,942],{"class":217},[207,1296,296],{"class":227},[207,1298,299],{"class":258},[207,1300,302],{"class":227},[207,1302,305],{"class":227},[207,1304,1305,1308,1310,1312,1314,1316,1319],{"class":209,"line":308},[207,1306,1307],{"class":217},"    status",[207,1309,296],{"class":227},[207,1311,299],{"class":258},[207,1313,302],{"class":227},[207,1315,280],{"class":227},[207,1317,1318],{"class":283},"active",[207,1320,287],{"class":227},[207,1322,1323],{"class":209,"line":313},[207,1324,248],{"emptyLinePlaceholder":247},[207,1326,1327,1329,1332,1334,1336],{"class":209,"line":327},[207,1328,255],{"class":254},[207,1330,1331],{"class":258}," Task",[207,1333,262],{"class":227},[207,1335,265],{"class":258},[207,1337,268],{"class":227},[207,1339,1340,1342,1344,1346,1349],{"class":209,"line":341},[207,1341,274],{"class":217},[207,1343,277],{"class":227},[207,1345,280],{"class":227},[207,1347,1348],{"class":283},"Task",[207,1350,287],{"class":227},[207,1352,1353,1356,1358,1360,1362,1364,1366,1368,1370,1372],{"class":209,"line":371},[207,1354,1355],{"class":217},"    quest",[207,1357,296],{"class":227},[207,1359,349],{"class":258},[207,1361,352],{"class":227},[207,1363,355],{"class":227},[207,1365,302],{"class":227},[207,1367,361],{"class":360},[207,1369,262],{"class":227},[207,1371,1288],{"class":360},[207,1373,368],{"class":227},[207,1375,1376,1379,1381,1383,1385],{"class":209,"line":390},[207,1377,1378],{"class":217},"    title",[207,1380,296],{"class":227},[207,1382,299],{"class":258},[207,1384,302],{"class":227},[207,1386,305],{"class":227},[207,1388,1389,1392,1394,1396,1398],{"class":209,"line":404},[207,1390,1391],{"class":217},"    done",[207,1393,296],{"class":227},[207,1395,902],{"class":258},[207,1397,302],{"class":227},[207,1399,1400],{"class":227}," False\n",[112,1402,1403,1406,1407,1410,1411,1414,1415,1418],{},[116,1404,1405],{},"parent_ref(Quest)"," creates a nullable ",[116,1408,1409],{},"int"," field that defaults to ",[116,1412,1413],{},"None",". CentauroDB enforces that it's set before the child can be written — you'll get an ",[116,1416,1417],{},"UnlinkedParentError"," if you try to persist an unlinked child.",[112,1420,1421],{},"You can forward any Pydantic field keyword arguments:",[198,1423,1425],{"className":200,"code":1424,"language":202,"meta":203,"style":203},"class Task(CentauroModel):\n    __centauro_name__ = \"Task\"\n    quest: int | None = parent_ref(Quest, description=\"FK to quest\")\n",[116,1426,1427,1439,1451],{"__ignoreMap":203},[207,1428,1429,1431,1433,1435,1437],{"class":209,"line":210},[207,1430,255],{"class":254},[207,1432,1331],{"class":258},[207,1434,262],{"class":227},[207,1436,265],{"class":258},[207,1438,268],{"class":227},[207,1440,1441,1443,1445,1447,1449],{"class":209,"line":244},[207,1442,274],{"class":217},[207,1444,277],{"class":227},[207,1446,280],{"class":227},[207,1448,1348],{"class":283},[207,1450,287],{"class":227},[207,1452,1453,1455,1457,1459,1461,1463,1465,1467,1469,1471,1473,1476,1478,1480,1483,1485],{"class":209,"line":251},[207,1454,1355],{"class":217},[207,1456,296],{"class":227},[207,1458,349],{"class":258},[207,1460,352],{"class":227},[207,1462,355],{"class":227},[207,1464,302],{"class":227},[207,1466,361],{"class":360},[207,1468,262],{"class":227},[207,1470,1288],{"class":360},[207,1472,228],{"class":227},[207,1474,1475],{"class":473}," description",[207,1477,277],{"class":227},[207,1479,444],{"class":227},[207,1481,1482],{"class":283},"FK to quest",[207,1484,444],{"class":227},[207,1486,368],{"class":227},[112,1488,1489,1491,1492,1495,1496,1499,1500,1505],{},[116,1490,118],{}," also accepts an ",[116,1493,1494],{},"on_delete"," keyword (default ",[116,1497,1498],{},"\"restrict\"",") that controls what happens when you delete a parent that still has children — see ",[1501,1502,1504],"a",{"href":1503},"#deleting-parents-and-children","Deleting parents and children"," below.",[1229,1507,1508,1509,1511],{},"The field defaults to ",[116,1510,1413],{}," to preserve the zero-migration guarantee. Enforcement happens at write/update time, not at model creation.",[125,1513,1515],{"id":1514},"linking-children-to-parents","Linking children to parents",[112,1517,1518],{},"There are two approaches, depending on your workflow.",[135,1520,1522],{"id":1521},"approach-1-pass-the-parent-object-directly","Approach 1: Pass the parent object directly",[112,1524,1525,1526,296],{},"You can assign a persisted parent object directly — CentauroDB auto-resolves it to ",[116,1527,122],{},[198,1529,1531],{"className":200,"code":1530,"language":202,"meta":203,"style":203},"from centaurodb import Engine, Collection\n\nengine = Engine()\ncoll = Collection(engine, \"quests\")\n\nquest = Quest(name=\"The Odyssey\")\ncoll.write_object(quest)\n\n# At construction\ntask = Task(title=\"Escape the Cyclops\", quest=quest)\nprint(task.quest)  # quest.row.id (int)\ncoll.write_object(task)\n\n# Or via assignment\ntask2 = Task(title=\"Resist the Sirens\")\ntask2.quest = quest  # resolves to quest.row.id\ncoll.write_object(task2)\n",[116,1532,1533,1548,1552,1562,1585,1589,1613,1628,1632,1637,1671,1691,1705,1709,1714,1738,1755],{"__ignoreMap":203},[207,1534,1535,1537,1539,1541,1543,1545],{"class":209,"line":210},[207,1536,214],{"class":213},[207,1538,218],{"class":217},[207,1540,221],{"class":213},[207,1542,224],{"class":217},[207,1544,228],{"class":227},[207,1546,1547],{"class":217}," Collection\n",[207,1549,1550],{"class":209,"line":244},[207,1551,248],{"emptyLinePlaceholder":247},[207,1553,1554,1556,1558,1560],{"class":209,"line":251},[207,1555,412],{"class":217},[207,1557,277],{"class":227},[207,1559,224],{"class":360},[207,1561,419],{"class":227},[207,1563,1564,1566,1568,1570,1572,1574,1576,1578,1581,1583],{"class":209,"line":271},[207,1565,425],{"class":217},[207,1567,277],{"class":227},[207,1569,231],{"class":360},[207,1571,262],{"class":227},[207,1573,434],{"class":360},[207,1575,228],{"class":227},[207,1577,280],{"class":227},[207,1579,1580],{"class":283},"quests",[207,1582,444],{"class":227},[207,1584,368],{"class":227},[207,1586,1587],{"class":209,"line":290},[207,1588,248],{"emptyLinePlaceholder":247},[207,1590,1591,1594,1596,1598,1600,1602,1604,1606,1609,1611],{"class":209,"line":308},[207,1592,1593],{"class":217},"quest ",[207,1595,277],{"class":227},[207,1597,1271],{"class":360},[207,1599,262],{"class":227},[207,1601,1057],{"class":473},[207,1603,277],{"class":227},[207,1605,444],{"class":227},[207,1607,1608],{"class":283},"The Odyssey",[207,1610,444],{"class":227},[207,1612,368],{"class":227},[207,1614,1615,1617,1619,1621,1623,1626],{"class":209,"line":313},[207,1616,491],{"class":217},[207,1618,494],{"class":227},[207,1620,497],{"class":360},[207,1622,262],{"class":227},[207,1624,1625],{"class":360},"quest",[207,1627,368],{"class":227},[207,1629,1630],{"class":209,"line":327},[207,1631,248],{"emptyLinePlaceholder":247},[207,1633,1634],{"class":209,"line":341},[207,1635,1636],{"class":457},"# At construction\n",[207,1638,1639,1642,1644,1646,1648,1651,1653,1655,1658,1660,1662,1665,1667,1669],{"class":209,"line":371},[207,1640,1641],{"class":217},"task ",[207,1643,277],{"class":227},[207,1645,1331],{"class":360},[207,1647,262],{"class":227},[207,1649,1650],{"class":473},"title",[207,1652,277],{"class":227},[207,1654,444],{"class":227},[207,1656,1657],{"class":283},"Escape the Cyclops",[207,1659,444],{"class":227},[207,1661,228],{"class":227},[207,1663,1664],{"class":473}," quest",[207,1666,277],{"class":227},[207,1668,1625],{"class":360},[207,1670,368],{"class":227},[207,1672,1673,1676,1678,1681,1683,1685,1688],{"class":209,"line":390},[207,1674,1675],{"class":360},"print",[207,1677,262],{"class":227},[207,1679,1680],{"class":360},"task",[207,1682,494],{"class":227},[207,1684,1625],{"class":705},[207,1686,1687],{"class":227},")",[207,1689,1690],{"class":457},"  # quest.row.id (int)\n",[207,1692,1693,1695,1697,1699,1701,1703],{"class":209,"line":404},[207,1694,491],{"class":217},[207,1696,494],{"class":227},[207,1698,497],{"class":360},[207,1700,262],{"class":227},[207,1702,1680],{"class":360},[207,1704,368],{"class":227},[207,1706,1707],{"class":209,"line":409},[207,1708,248],{"emptyLinePlaceholder":247},[207,1710,1711],{"class":209,"line":422},[207,1712,1713],{"class":457},"# Or via assignment\n",[207,1715,1716,1719,1721,1723,1725,1727,1729,1731,1734,1736],{"class":209,"line":449},[207,1717,1718],{"class":217},"task2 ",[207,1720,277],{"class":227},[207,1722,1331],{"class":360},[207,1724,262],{"class":227},[207,1726,1650],{"class":473},[207,1728,277],{"class":227},[207,1730,444],{"class":227},[207,1732,1733],{"class":283},"Resist the Sirens",[207,1735,444],{"class":227},[207,1737,368],{"class":227},[207,1739,1740,1743,1745,1747,1749,1752],{"class":209,"line":454},[207,1741,1742],{"class":217},"task2",[207,1744,494],{"class":227},[207,1746,1625],{"class":705},[207,1748,302],{"class":227},[207,1750,1751],{"class":217}," quest  ",[207,1753,1754],{"class":457},"# resolves to quest.row.id\n",[207,1756,1757,1759,1761,1763,1765,1767],{"class":209,"line":461},[207,1758,491],{"class":217},[207,1760,494],{"class":227},[207,1762,497],{"class":360},[207,1764,262],{"class":227},[207,1766,1742],{"class":360},[207,1768,368],{"class":227},[135,1770,1772,1773],{"id":1771},"approach-2-one-step-with-write_child","Approach 2: One-step with ",[116,1774,525],{},[112,1776,1777],{},"Link and write in a single call:",[198,1779,1781],{"className":200,"code":1780,"language":202,"meta":203,"style":203},"task3 = Task(title=\"String the great bow\")\ncoll.write_child(task3, parent=quest)\n\n# Both linked and persisted\nprint(task3.quest)   # quest.row.id\nprint(task3.row.id)    # auto-assigned\n",[116,1782,1783,1807,1830,1834,1839,1856],{"__ignoreMap":203},[207,1784,1785,1788,1790,1792,1794,1796,1798,1800,1803,1805],{"class":209,"line":210},[207,1786,1787],{"class":217},"task3 ",[207,1789,277],{"class":227},[207,1791,1331],{"class":360},[207,1793,262],{"class":227},[207,1795,1650],{"class":473},[207,1797,277],{"class":227},[207,1799,444],{"class":227},[207,1801,1802],{"class":283},"String the great bow",[207,1804,444],{"class":227},[207,1806,368],{"class":227},[207,1808,1809,1811,1813,1815,1817,1820,1822,1824,1826,1828],{"class":209,"line":244},[207,1810,491],{"class":217},[207,1812,494],{"class":227},[207,1814,525],{"class":360},[207,1816,262],{"class":227},[207,1818,1819],{"class":360},"task3",[207,1821,228],{"class":227},[207,1823,562],{"class":473},[207,1825,277],{"class":227},[207,1827,1625],{"class":360},[207,1829,368],{"class":227},[207,1831,1832],{"class":209,"line":251},[207,1833,248],{"emptyLinePlaceholder":247},[207,1835,1836],{"class":209,"line":271},[207,1837,1838],{"class":457},"# Both linked and persisted\n",[207,1840,1841,1843,1845,1847,1849,1851,1853],{"class":209,"line":290},[207,1842,1675],{"class":360},[207,1844,262],{"class":227},[207,1846,1819],{"class":360},[207,1848,494],{"class":227},[207,1850,1625],{"class":705},[207,1852,1687],{"class":227},[207,1854,1855],{"class":457},"   # quest.row.id\n",[207,1857,1858,1860,1862,1864,1866,1868,1870,1872,1874],{"class":209,"line":308},[207,1859,1675],{"class":360},[207,1861,262],{"class":227},[207,1863,1819],{"class":360},[207,1865,494],{"class":227},[207,1867,722],{"class":705},[207,1869,494],{"class":227},[207,1871,727],{"class":705},[207,1873,1687],{"class":227},[207,1875,1876],{"class":457},"    # auto-assigned\n",[112,1878,1879,1881,1882,1884],{},[116,1880,525],{}," auto-discovers the matching ",[116,1883,118],{}," field by inspecting the child's model class.",[1886,1887,1888,1889,1894],"warning",{},"The parent must be persisted before you can use it. Passing an unpersisted parent raises an exception. See ",[1501,1890,1892],{"href":1891},"/api/exceptions#unlinkedparenterror",[116,1893,1417],{}," for details.",[125,1896,1898],{"id":1897},"querying-children","Querying children",[135,1900,1902,1903],{"id":1901},"using-children_of","Using ",[116,1904,163],{},[112,1906,1907],{},"Read all children linked to a parent:",[198,1909,1911],{"className":200,"code":1910,"language":202,"meta":203,"style":203},"tasks = coll.children_of(quest, Task)\n\nfor t in tasks:\n    print(t.title, \"✓\" if t.done else \"○\")\n# Escape the Cyclops ○\n# Resist the Sirens ○\n# String the great bow ○\n",[116,1912,1913,1936,1940,1957,2003,2008,2013],{"__ignoreMap":203},[207,1914,1915,1918,1920,1922,1924,1926,1928,1930,1932,1934],{"class":209,"line":210},[207,1916,1917],{"class":217},"tasks ",[207,1919,277],{"class":227},[207,1921,687],{"class":217},[207,1923,494],{"class":227},[207,1925,163],{"class":360},[207,1927,262],{"class":227},[207,1929,1625],{"class":360},[207,1931,228],{"class":227},[207,1933,1331],{"class":360},[207,1935,368],{"class":227},[207,1937,1938],{"class":209,"line":244},[207,1939,248],{"emptyLinePlaceholder":247},[207,1941,1942,1945,1948,1951,1954],{"class":209,"line":251},[207,1943,1944],{"class":213},"for",[207,1946,1947],{"class":217}," t ",[207,1949,1950],{"class":213},"in",[207,1952,1953],{"class":217}," tasks",[207,1955,1956],{"class":227},":\n",[207,1958,1959,1962,1964,1967,1969,1971,1973,1975,1978,1980,1983,1986,1988,1991,1994,1996,1999,2001],{"class":209,"line":271},[207,1960,1961],{"class":360},"    print",[207,1963,262],{"class":227},[207,1965,1966],{"class":360},"t",[207,1968,494],{"class":227},[207,1970,1650],{"class":705},[207,1972,228],{"class":227},[207,1974,280],{"class":227},[207,1976,1977],{"class":283},"✓",[207,1979,444],{"class":227},[207,1981,1982],{"class":213}," if",[207,1984,1985],{"class":360}," t",[207,1987,494],{"class":227},[207,1989,1990],{"class":705},"done",[207,1992,1993],{"class":213}," else",[207,1995,280],{"class":227},[207,1997,1998],{"class":283},"○",[207,2000,444],{"class":227},[207,2002,368],{"class":227},[207,2004,2005],{"class":209,"line":290},[207,2006,2007],{"class":457},"# Escape the Cyclops ○\n",[207,2009,2010],{"class":209,"line":308},[207,2011,2012],{"class":457},"# Resist the Sirens ○\n",[207,2014,2015],{"class":209,"line":313},[207,2016,2017],{"class":457},"# String the great bow ○\n",[112,2019,2020,2021,2024],{},"Pass ",[116,2022,2023],{},"raw=True"," to get raw database rows instead of model instances.",[135,2026,1902,2028,2030],{"id":2027},"using-read_objects-with-conditions",[116,2029,167],{}," with conditions",[112,2032,2033],{},"For more complex queries, combine the parent filter with other conditions:",[198,2035,2037],{"className":200,"code":2036,"language":202,"meta":203,"style":203},"# All tasks for this quest\nresults = coll.read_objects(\n    Task.fields.quest == quest.row.id\n)\n\n# Unfinished tasks for this quest\nresults = coll.read_objects(\n    Task.fields.quest == quest.row.id,\n    Task.fields.done == False,\n)\n\n# Combine with OR: tasks involving monsters or navigation\nresults = coll.read_objects(\n    Task.fields.quest == quest.row.id,\n    (Task.fields.title.like(\"%Cyclops%\")) | (Task.fields.title.like(\"%Sirens%\")),\n)\n",[116,2038,2039,2044,2059,2085,2089,2093,2098,2112,2138,2155,2159,2163,2168,2182,2208,2271],{"__ignoreMap":203},[207,2040,2041],{"class":209,"line":210},[207,2042,2043],{"class":457},"# All tasks for this quest\n",[207,2045,2046,2049,2051,2053,2055,2057],{"class":209,"line":244},[207,2047,2048],{"class":217},"results ",[207,2050,277],{"class":227},[207,2052,687],{"class":217},[207,2054,494],{"class":227},[207,2056,167],{"class":360},[207,2058,694],{"class":227},[207,2060,2061,2064,2066,2068,2070,2072,2074,2076,2078,2080,2082],{"class":209,"line":251},[207,2062,2063],{"class":360},"    Task",[207,2065,494],{"class":227},[207,2067,706],{"class":705},[207,2069,494],{"class":227},[207,2071,1625],{"class":705},[207,2073,714],{"class":227},[207,2075,1664],{"class":360},[207,2077,494],{"class":227},[207,2079,722],{"class":705},[207,2081,494],{"class":227},[207,2083,2084],{"class":705},"id\n",[207,2086,2087],{"class":209,"line":271},[207,2088,368],{"class":227},[207,2090,2091],{"class":209,"line":290},[207,2092,248],{"emptyLinePlaceholder":247},[207,2094,2095],{"class":209,"line":308},[207,2096,2097],{"class":457},"# Unfinished tasks for this quest\n",[207,2099,2100,2102,2104,2106,2108,2110],{"class":209,"line":313},[207,2101,2048],{"class":217},[207,2103,277],{"class":227},[207,2105,687],{"class":217},[207,2107,494],{"class":227},[207,2109,167],{"class":360},[207,2111,694],{"class":227},[207,2113,2114,2116,2118,2120,2122,2124,2126,2128,2130,2132,2134,2136],{"class":209,"line":327},[207,2115,2063],{"class":360},[207,2117,494],{"class":227},[207,2119,706],{"class":705},[207,2121,494],{"class":227},[207,2123,1625],{"class":705},[207,2125,714],{"class":227},[207,2127,1664],{"class":360},[207,2129,494],{"class":227},[207,2131,722],{"class":705},[207,2133,494],{"class":227},[207,2135,727],{"class":705},[207,2137,730],{"class":227},[207,2139,2140,2142,2144,2146,2148,2150,2152],{"class":209,"line":341},[207,2141,2063],{"class":360},[207,2143,494],{"class":227},[207,2145,706],{"class":705},[207,2147,494],{"class":227},[207,2149,1990],{"class":705},[207,2151,714],{"class":227},[207,2153,2154],{"class":227}," False,\n",[207,2156,2157],{"class":209,"line":371},[207,2158,368],{"class":227},[207,2160,2161],{"class":209,"line":390},[207,2162,248],{"emptyLinePlaceholder":247},[207,2164,2165],{"class":209,"line":404},[207,2166,2167],{"class":457},"# Combine with OR: tasks involving monsters or navigation\n",[207,2169,2170,2172,2174,2176,2178,2180],{"class":209,"line":409},[207,2171,2048],{"class":217},[207,2173,277],{"class":227},[207,2175,687],{"class":217},[207,2177,494],{"class":227},[207,2179,167],{"class":360},[207,2181,694],{"class":227},[207,2183,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206],{"class":209,"line":422},[207,2185,2063],{"class":360},[207,2187,494],{"class":227},[207,2189,706],{"class":705},[207,2191,494],{"class":227},[207,2193,1625],{"class":705},[207,2195,714],{"class":227},[207,2197,1664],{"class":360},[207,2199,494],{"class":227},[207,2201,722],{"class":705},[207,2203,494],{"class":227},[207,2205,727],{"class":705},[207,2207,730],{"class":227},[207,2209,2210,2213,2215,2217,2219,2221,2223,2225,2228,2230,2232,2235,2237,2240,2242,2245,2247,2249,2251,2253,2255,2257,2259,2261,2263,2266,2268],{"class":209,"line":449},[207,2211,2212],{"class":227},"    (",[207,2214,1348],{"class":360},[207,2216,494],{"class":227},[207,2218,706],{"class":705},[207,2220,494],{"class":227},[207,2222,1650],{"class":705},[207,2224,494],{"class":227},[207,2226,2227],{"class":360},"like",[207,2229,262],{"class":227},[207,2231,444],{"class":227},[207,2233,2234],{"class":283},"%Cyclops%",[207,2236,444],{"class":227},[207,2238,2239],{"class":227},"))",[207,2241,352],{"class":227},[207,2243,2244],{"class":227}," (",[207,2246,1348],{"class":360},[207,2248,494],{"class":227},[207,2250,706],{"class":705},[207,2252,494],{"class":227},[207,2254,1650],{"class":705},[207,2256,494],{"class":227},[207,2258,2227],{"class":360},[207,2260,262],{"class":227},[207,2262,444],{"class":227},[207,2264,2265],{"class":283},"%Sirens%",[207,2267,444],{"class":227},[207,2269,2270],{"class":227},")),\n",[207,2272,2273],{"class":209,"line":454},[207,2274,368],{"class":227},[125,2276,2278],{"id":2277},"update-validation","Update validation",[112,2280,2281,2283,2284,2286,2287,296],{},[116,2282,1174],{}," also validates parent refs. Nulling out a ",[116,2285,118],{}," and trying to update raises ",[116,2288,1417],{},[198,2290,2292],{"className":200,"code":2291,"language":202,"meta":203,"style":203},"task = coll.read_object_by_id(1, Task)\ntask.quest = None\ncoll.update_object(task)  # raises UnlinkedParentError\n",[116,2293,2294,2319,2332],{"__ignoreMap":203},[207,2295,2296,2298,2300,2302,2304,2307,2309,2313,2315,2317],{"class":209,"line":210},[207,2297,1641],{"class":217},[207,2299,277],{"class":227},[207,2301,687],{"class":217},[207,2303,494],{"class":227},[207,2305,2306],{"class":360},"read_object_by_id",[207,2308,262],{"class":227},[207,2310,2312],{"class":2311},"sbssI","1",[207,2314,228],{"class":227},[207,2316,1331],{"class":360},[207,2318,368],{"class":227},[207,2320,2321,2323,2325,2327,2329],{"class":209,"line":244},[207,2322,1680],{"class":217},[207,2324,494],{"class":227},[207,2326,1625],{"class":705},[207,2328,302],{"class":227},[207,2330,2331],{"class":227}," None\n",[207,2333,2334,2336,2338,2340,2342,2344,2346],{"class":209,"line":251},[207,2335,491],{"class":217},[207,2337,494],{"class":227},[207,2339,1174],{"class":360},[207,2341,262],{"class":227},[207,2343,1680],{"class":360},[207,2345,1687],{"class":227},[207,2347,2348],{"class":457},"  # raises UnlinkedParentError\n",[125,2350,1504],{"id":2351},"deleting-parents-and-children",[112,2353,2354,2355,2357,2358,2361,2362,2368],{},"By default, ",[116,2356,118],{}," uses ",[116,2359,2360],{},"on_delete=\"restrict\"",": deleting a parent that still has children raises ",[1501,2363,2365],{"href":2364},"/api/exceptions#parenthaschildrenerror",[116,2366,2367],{},"ParentHasChildrenError",", and the parent row is left untouched. This prevents orphaned children pointing at an id that no longer exists.",[112,2370,2371],{},"Delete the children first, then the parent:",[198,2373,2375],{"className":200,"code":2374,"language":202,"meta":203,"style":203},"coll.delete_object(quest)  # raises ParentHasChildrenError — tasks still exist\n\n# Correct order: children first\ncoll.delete_objects(Task.fields.quest == quest.row.id)\ncoll.delete_object(quest)  # works\n",[116,2376,2377,2395,2399,2404,2439],{"__ignoreMap":203},[207,2378,2379,2381,2383,2386,2388,2390,2392],{"class":209,"line":210},[207,2380,491],{"class":217},[207,2382,494],{"class":227},[207,2384,2385],{"class":360},"delete_object",[207,2387,262],{"class":227},[207,2389,1625],{"class":360},[207,2391,1687],{"class":227},[207,2393,2394],{"class":457},"  # raises ParentHasChildrenError — tasks still exist\n",[207,2396,2397],{"class":209,"line":244},[207,2398,248],{"emptyLinePlaceholder":247},[207,2400,2401],{"class":209,"line":251},[207,2402,2403],{"class":457},"# Correct order: children first\n",[207,2405,2406,2408,2410,2413,2415,2417,2419,2421,2423,2425,2427,2429,2431,2433,2435,2437],{"class":209,"line":271},[207,2407,491],{"class":217},[207,2409,494],{"class":227},[207,2411,2412],{"class":360},"delete_objects",[207,2414,262],{"class":227},[207,2416,1348],{"class":360},[207,2418,494],{"class":227},[207,2420,706],{"class":705},[207,2422,494],{"class":227},[207,2424,1625],{"class":705},[207,2426,714],{"class":227},[207,2428,1664],{"class":360},[207,2430,494],{"class":227},[207,2432,722],{"class":705},[207,2434,494],{"class":227},[207,2436,727],{"class":705},[207,2438,368],{"class":227},[207,2440,2441,2443,2445,2447,2449,2451,2453],{"class":209,"line":290},[207,2442,491],{"class":217},[207,2444,494],{"class":227},[207,2446,2385],{"class":360},[207,2448,262],{"class":227},[207,2450,1625],{"class":360},[207,2452,1687],{"class":227},[207,2454,2455],{"class":457},"  # works\n",[1886,2457,2458,193,2461,2464,2465,2467,2468,2471],{},[116,2459,2460],{},"\"cascade\"",[116,2462,2463],{},"\"set_null\""," are accepted as ",[116,2466,1494],{}," values at class definition, but a delete that would trigger them raises ",[116,2469,2470],{},"NotImplementedError",". The call shape is committed now so future releases can implement them without breaking your model definitions — don't rely on them yet.",[112,2473,2474],{},"This restrict-by-default behavior is a deliberate change from the never-published 0.5.0 internal snapshot, which silently orphaned children when their parent was deleted.",[125,2476,2478],{"id":2477},"inheritance","Inheritance",[112,2480,2481,2482,2484],{},"Subclasses inherit ",[116,2483,118],{}," fields from their parent class:",[198,2486,2488],{"className":200,"code":2487,"language":202,"meta":203,"style":203},"class UrgentTask(Task):\n    __centauro_name__ = \"UrgentTask\"\n    deadline: str = \"\"\n\n# UrgentTask inherits the quest parent_ref from Task\nurgent = UrgentTask(title=\"Defeat Scylla before dawn\", deadline=\"2025-06-15\")\ncoll.write_child(urgent, parent=quest)\n\nchildren = coll.children_of(quest, UrgentTask)\n",[116,2489,2490,2503,2516,2529,2533,2538,2576,2599,2603],{"__ignoreMap":203},[207,2491,2492,2494,2497,2499,2501],{"class":209,"line":210},[207,2493,255],{"class":254},[207,2495,2496],{"class":258}," UrgentTask",[207,2498,262],{"class":227},[207,2500,1348],{"class":258},[207,2502,268],{"class":227},[207,2504,2505,2507,2509,2511,2514],{"class":209,"line":244},[207,2506,274],{"class":217},[207,2508,277],{"class":227},[207,2510,280],{"class":227},[207,2512,2513],{"class":283},"UrgentTask",[207,2515,287],{"class":227},[207,2517,2518,2521,2523,2525,2527],{"class":209,"line":251},[207,2519,2520],{"class":217},"    deadline",[207,2522,296],{"class":227},[207,2524,299],{"class":258},[207,2526,302],{"class":227},[207,2528,305],{"class":227},[207,2530,2531],{"class":209,"line":271},[207,2532,248],{"emptyLinePlaceholder":247},[207,2534,2535],{"class":209,"line":290},[207,2536,2537],{"class":457},"# UrgentTask inherits the quest parent_ref from Task\n",[207,2539,2540,2543,2545,2547,2549,2551,2553,2555,2558,2560,2562,2565,2567,2569,2572,2574],{"class":209,"line":308},[207,2541,2542],{"class":217},"urgent ",[207,2544,277],{"class":227},[207,2546,2496],{"class":360},[207,2548,262],{"class":227},[207,2550,1650],{"class":473},[207,2552,277],{"class":227},[207,2554,444],{"class":227},[207,2556,2557],{"class":283},"Defeat Scylla before dawn",[207,2559,444],{"class":227},[207,2561,228],{"class":227},[207,2563,2564],{"class":473}," deadline",[207,2566,277],{"class":227},[207,2568,444],{"class":227},[207,2570,2571],{"class":283},"2025-06-15",[207,2573,444],{"class":227},[207,2575,368],{"class":227},[207,2577,2578,2580,2582,2584,2586,2589,2591,2593,2595,2597],{"class":209,"line":313},[207,2579,491],{"class":217},[207,2581,494],{"class":227},[207,2583,525],{"class":360},[207,2585,262],{"class":227},[207,2587,2588],{"class":360},"urgent",[207,2590,228],{"class":227},[207,2592,562],{"class":473},[207,2594,277],{"class":227},[207,2596,1625],{"class":360},[207,2598,368],{"class":227},[207,2600,2601],{"class":209,"line":327},[207,2602,248],{"emptyLinePlaceholder":247},[207,2604,2605,2608,2610,2612,2614,2616,2618,2620,2622,2624],{"class":209,"line":341},[207,2606,2607],{"class":217},"children ",[207,2609,277],{"class":227},[207,2611,687],{"class":217},[207,2613,494],{"class":227},[207,2615,163],{"class":360},[207,2617,262],{"class":227},[207,2619,1625],{"class":360},[207,2621,228],{"class":227},[207,2623,2496],{"class":360},[207,2625,368],{"class":227},[125,2627,2629],{"id":2628},"multiple-parent-refs","Multiple parent refs",[112,2631,2632],{},"A child model can reference multiple parent types:",[198,2634,2636],{"className":200,"code":2635,"language":202,"meta":203,"style":203},"class Crew(CentauroModel):\n    __centauro_name__ = \"Crew\"\n    name: str = \"\"\n\nclass Assignment(CentauroModel):\n    __centauro_name__ = \"Assignment\"\n    quest: int | None = parent_ref(Quest)\n    crew: int | None = parent_ref(Crew)\n    role: str = \"\"\n",[116,2637,2638,2651,2664,2676,2680,2693,2706,2728,2751],{"__ignoreMap":203},[207,2639,2640,2642,2645,2647,2649],{"class":209,"line":210},[207,2641,255],{"class":254},[207,2643,2644],{"class":258}," Crew",[207,2646,262],{"class":227},[207,2648,265],{"class":258},[207,2650,268],{"class":227},[207,2652,2653,2655,2657,2659,2662],{"class":209,"line":244},[207,2654,274],{"class":217},[207,2656,277],{"class":227},[207,2658,280],{"class":227},[207,2660,2661],{"class":283},"Crew",[207,2663,287],{"class":227},[207,2665,2666,2668,2670,2672,2674],{"class":209,"line":251},[207,2667,942],{"class":217},[207,2669,296],{"class":227},[207,2671,299],{"class":258},[207,2673,302],{"class":227},[207,2675,305],{"class":227},[207,2677,2678],{"class":209,"line":271},[207,2679,248],{"emptyLinePlaceholder":247},[207,2681,2682,2684,2687,2689,2691],{"class":209,"line":290},[207,2683,255],{"class":254},[207,2685,2686],{"class":258}," Assignment",[207,2688,262],{"class":227},[207,2690,265],{"class":258},[207,2692,268],{"class":227},[207,2694,2695,2697,2699,2701,2704],{"class":209,"line":308},[207,2696,274],{"class":217},[207,2698,277],{"class":227},[207,2700,280],{"class":227},[207,2702,2703],{"class":283},"Assignment",[207,2705,287],{"class":227},[207,2707,2708,2710,2712,2714,2716,2718,2720,2722,2724,2726],{"class":209,"line":313},[207,2709,1355],{"class":217},[207,2711,296],{"class":227},[207,2713,349],{"class":258},[207,2715,352],{"class":227},[207,2717,355],{"class":227},[207,2719,302],{"class":227},[207,2721,361],{"class":360},[207,2723,262],{"class":227},[207,2725,1288],{"class":360},[207,2727,368],{"class":227},[207,2729,2730,2733,2735,2737,2739,2741,2743,2745,2747,2749],{"class":209,"line":327},[207,2731,2732],{"class":217},"    crew",[207,2734,296],{"class":227},[207,2736,349],{"class":258},[207,2738,352],{"class":227},[207,2740,355],{"class":227},[207,2742,302],{"class":227},[207,2744,361],{"class":360},[207,2746,262],{"class":227},[207,2748,2661],{"class":360},[207,2750,368],{"class":227},[207,2752,2753,2756,2758,2760,2762],{"class":209,"line":341},[207,2754,2755],{"class":217},"    role",[207,2757,296],{"class":227},[207,2759,299],{"class":258},[207,2761,302],{"class":227},[207,2763,305],{"class":227},[112,2765,2766],{},"Pass both parents at construction, or assign them individually before writing:",[198,2768,2770],{"className":200,"code":2769,"language":202,"meta":203,"style":203},"coll.write_object(crew)\n\n# At construction\nassignment = Assignment(role=\"captain\", quest=quest, crew=crew)\ncoll.write_object(assignment)\n\n# Or assign individually\nassignment2 = Assignment(role=\"oarsman\")\nassignment2.quest = quest\nassignment2.crew = crew\ncoll.write_object(assignment2)\n",[116,2771,2772,2787,2791,2795,2837,2852,2856,2861,2885,2899,2912],{"__ignoreMap":203},[207,2773,2774,2776,2778,2780,2782,2785],{"class":209,"line":210},[207,2775,491],{"class":217},[207,2777,494],{"class":227},[207,2779,497],{"class":360},[207,2781,262],{"class":227},[207,2783,2784],{"class":360},"crew",[207,2786,368],{"class":227},[207,2788,2789],{"class":209,"line":244},[207,2790,248],{"emptyLinePlaceholder":247},[207,2792,2793],{"class":209,"line":251},[207,2794,1636],{"class":457},[207,2796,2797,2800,2802,2804,2806,2809,2811,2813,2816,2818,2820,2822,2824,2826,2828,2831,2833,2835],{"class":209,"line":271},[207,2798,2799],{"class":217},"assignment ",[207,2801,277],{"class":227},[207,2803,2686],{"class":360},[207,2805,262],{"class":227},[207,2807,2808],{"class":473},"role",[207,2810,277],{"class":227},[207,2812,444],{"class":227},[207,2814,2815],{"class":283},"captain",[207,2817,444],{"class":227},[207,2819,228],{"class":227},[207,2821,1664],{"class":473},[207,2823,277],{"class":227},[207,2825,1625],{"class":360},[207,2827,228],{"class":227},[207,2829,2830],{"class":473}," crew",[207,2832,277],{"class":227},[207,2834,2784],{"class":360},[207,2836,368],{"class":227},[207,2838,2839,2841,2843,2845,2847,2850],{"class":209,"line":290},[207,2840,491],{"class":217},[207,2842,494],{"class":227},[207,2844,497],{"class":360},[207,2846,262],{"class":227},[207,2848,2849],{"class":360},"assignment",[207,2851,368],{"class":227},[207,2853,2854],{"class":209,"line":308},[207,2855,248],{"emptyLinePlaceholder":247},[207,2857,2858],{"class":209,"line":313},[207,2859,2860],{"class":457},"# Or assign individually\n",[207,2862,2863,2866,2868,2870,2872,2874,2876,2878,2881,2883],{"class":209,"line":327},[207,2864,2865],{"class":217},"assignment2 ",[207,2867,277],{"class":227},[207,2869,2686],{"class":360},[207,2871,262],{"class":227},[207,2873,2808],{"class":473},[207,2875,277],{"class":227},[207,2877,444],{"class":227},[207,2879,2880],{"class":283},"oarsman",[207,2882,444],{"class":227},[207,2884,368],{"class":227},[207,2886,2887,2890,2892,2894,2896],{"class":209,"line":341},[207,2888,2889],{"class":217},"assignment2",[207,2891,494],{"class":227},[207,2893,1625],{"class":705},[207,2895,302],{"class":227},[207,2897,2898],{"class":217}," quest\n",[207,2900,2901,2903,2905,2907,2909],{"class":209,"line":371},[207,2902,2889],{"class":217},[207,2904,494],{"class":227},[207,2906,2784],{"class":705},[207,2908,302],{"class":227},[207,2910,2911],{"class":217}," crew\n",[207,2913,2914,2916,2918,2920,2922,2924],{"class":209,"line":390},[207,2915,491],{"class":217},[207,2917,494],{"class":227},[207,2919,497],{"class":360},[207,2921,262],{"class":227},[207,2923,2889],{"class":360},[207,2925,368],{"class":227},[1886,2927,2928,2931,2932,2934,2935,2937,2938,494],{},[150,2929,2930],{},"All"," ",[116,2933,118],{}," fields must be set before writing or updating. If any remain ",[116,2936,1413],{},", it raises ",[116,2939,1417],{},[112,2941,2942,2943,2945,2946,2949,2950,2952,2953,2956],{},"When a child has multiple ",[116,2944,118],{}," fields pointing to the ",[150,2947,2948],{},"same"," parent type, ",[116,2951,525],{}," raises ",[116,2954,2955],{},"TypeError"," — set the fields directly instead.",[125,2958,2960],{"id":2959},"views-and-indexes-on-relations","Views and indexes on relations",[112,2962,2963,2965,2966,193,2969,2973],{},[116,2964,118],{}," fields work with ",[1501,2967,2968],{"href":44},"views",[1501,2970,2972],{"href":2971},"/essentials/views#standalone-indexes","indexes"," like any other field:",[198,2975,2977],{"className":200,"code":2976,"language":202,"meta":203,"style":203},"coll.create_view(\"board\", Task, include_fields=[\"quest\", \"title\", \"done\"])\ncoll.create_index(\"quest\")\n",[116,2978,2979,3034],{"__ignoreMap":203},[207,2980,2981,2983,2985,2988,2990,2992,2995,2997,2999,3001,3003,3006,3009,3011,3013,3015,3017,3019,3021,3023,3025,3027,3029,3031],{"class":209,"line":210},[207,2982,491],{"class":217},[207,2984,494],{"class":227},[207,2986,2987],{"class":360},"create_view",[207,2989,262],{"class":227},[207,2991,444],{"class":227},[207,2993,2994],{"class":283},"board",[207,2996,444],{"class":227},[207,2998,228],{"class":227},[207,3000,1331],{"class":360},[207,3002,228],{"class":227},[207,3004,3005],{"class":473}," include_fields",[207,3007,3008],{"class":227},"=[",[207,3010,444],{"class":227},[207,3012,1625],{"class":283},[207,3014,444],{"class":227},[207,3016,228],{"class":227},[207,3018,280],{"class":227},[207,3020,1650],{"class":283},[207,3022,444],{"class":227},[207,3024,228],{"class":227},[207,3026,280],{"class":227},[207,3028,1990],{"class":283},[207,3030,444],{"class":227},[207,3032,3033],{"class":227},"])\n",[207,3035,3036,3038,3040,3043,3045,3047,3049,3051],{"class":209,"line":244},[207,3037,491],{"class":217},[207,3039,494],{"class":227},[207,3041,3042],{"class":360},"create_index",[207,3044,262],{"class":227},[207,3046,444],{"class":227},[207,3048,1625],{"class":283},[207,3050,444],{"class":227},[207,3052,368],{"class":227},[112,3054,3055],{},"Query parent-child relationships via SQL:",[198,3057,3059],{"className":200,"code":3058,"language":202,"meta":203,"style":203},"df = coll.sql_select(\"\"\"\n    SELECT title, done\n    FROM quests_view_board\n    WHERE quest = ?\n    ORDER BY title\n\"\"\", (quest.row.id,))\n",[116,3060,3061,3080,3085,3090,3095,3100],{"__ignoreMap":203},[207,3062,3063,3066,3068,3070,3072,3075,3077],{"class":209,"line":210},[207,3064,3065],{"class":217},"df ",[207,3067,277],{"class":227},[207,3069,687],{"class":217},[207,3071,494],{"class":227},[207,3073,3074],{"class":360},"sql_select",[207,3076,262],{"class":227},[207,3078,3079],{"class":227},"\"\"\"\n",[207,3081,3082],{"class":209,"line":244},[207,3083,3084],{"class":283},"    SELECT title, done\n",[207,3086,3087],{"class":209,"line":251},[207,3088,3089],{"class":283},"    FROM quests_view_board\n",[207,3091,3092],{"class":209,"line":271},[207,3093,3094],{"class":283},"    WHERE quest = ?\n",[207,3096,3097],{"class":209,"line":290},[207,3098,3099],{"class":283},"    ORDER BY title\n",[207,3101,3102,3105,3107,3109,3111,3113,3115,3117,3119],{"class":209,"line":308},[207,3103,3104],{"class":227},"\"\"\"",[207,3106,228],{"class":227},[207,3108,2244],{"class":227},[207,3110,1625],{"class":360},[207,3112,494],{"class":227},[207,3114,722],{"class":705},[207,3116,494],{"class":227},[207,3118,727],{"class":705},[207,3120,3121],{"class":227},",))\n",[125,3123,3125],{"id":3124},"keep-related-models-in-one-collection","Keep related models in one collection",[112,3127,3128,3129,3132,3133,3136,3137,3140,3141,3143,3144,3147],{},"Parent-child models must live in the ",[150,3130,3131],{},"same collection",". This is not an arbitrary rule — it follows directly from CentauroDB's single-collection query model: each query targets one ",[116,3134,3135],{},"{name}_objects"," table, and parent-child relationships are expressed as filters on that table's ",[116,3138,3139],{},"meta"," JSON, not as cross-table JOINs. Row IDs are per-table (an autoincrement counter inside each ",[116,3142,3135],{},"), so a child row pointing at \"id 1\" only makes sense relative to the ",[150,3145,3146],{},"one"," collection that owns both rows. Mixing collections would silently mismatch unrelated IDs.",[198,3149,3151],{"className":200,"code":3150,"language":202,"meta":203,"style":203},"# Good — parent and child in the same collection\ncoll = Collection(engine, \"quests\")\ncoll.write_object(quest)\ncoll.write_child(task, parent=quest)\nchildren = coll.children_of(quest, Task)\n\n# Bad — separate collections break the relationship\nquests = Collection(engine, \"quests\")\ntasks = Collection(engine, \"tasks\")\n# IDs in quests_objects and tasks_objects are independent\n# — a quest with id=1 and an unrelated object with id=1\n#    in another collection could create false matches\n",[116,3152,3153,3158,3180,3194,3216,3238,3242,3247,3270,3293,3298,3303],{"__ignoreMap":203},[207,3154,3155],{"class":209,"line":210},[207,3156,3157],{"class":457},"# Good — parent and child in the same collection\n",[207,3159,3160,3162,3164,3166,3168,3170,3172,3174,3176,3178],{"class":209,"line":244},[207,3161,425],{"class":217},[207,3163,277],{"class":227},[207,3165,231],{"class":360},[207,3167,262],{"class":227},[207,3169,434],{"class":360},[207,3171,228],{"class":227},[207,3173,280],{"class":227},[207,3175,1580],{"class":283},[207,3177,444],{"class":227},[207,3179,368],{"class":227},[207,3181,3182,3184,3186,3188,3190,3192],{"class":209,"line":251},[207,3183,491],{"class":217},[207,3185,494],{"class":227},[207,3187,497],{"class":360},[207,3189,262],{"class":227},[207,3191,1625],{"class":360},[207,3193,368],{"class":227},[207,3195,3196,3198,3200,3202,3204,3206,3208,3210,3212,3214],{"class":209,"line":271},[207,3197,491],{"class":217},[207,3199,494],{"class":227},[207,3201,525],{"class":360},[207,3203,262],{"class":227},[207,3205,1680],{"class":360},[207,3207,228],{"class":227},[207,3209,562],{"class":473},[207,3211,277],{"class":227},[207,3213,1625],{"class":360},[207,3215,368],{"class":227},[207,3217,3218,3220,3222,3224,3226,3228,3230,3232,3234,3236],{"class":209,"line":290},[207,3219,2607],{"class":217},[207,3221,277],{"class":227},[207,3223,687],{"class":217},[207,3225,494],{"class":227},[207,3227,163],{"class":360},[207,3229,262],{"class":227},[207,3231,1625],{"class":360},[207,3233,228],{"class":227},[207,3235,1331],{"class":360},[207,3237,368],{"class":227},[207,3239,3240],{"class":209,"line":308},[207,3241,248],{"emptyLinePlaceholder":247},[207,3243,3244],{"class":209,"line":313},[207,3245,3246],{"class":457},"# Bad — separate collections break the relationship\n",[207,3248,3249,3252,3254,3256,3258,3260,3262,3264,3266,3268],{"class":209,"line":327},[207,3250,3251],{"class":217},"quests ",[207,3253,277],{"class":227},[207,3255,231],{"class":360},[207,3257,262],{"class":227},[207,3259,434],{"class":360},[207,3261,228],{"class":227},[207,3263,280],{"class":227},[207,3265,1580],{"class":283},[207,3267,444],{"class":227},[207,3269,368],{"class":227},[207,3271,3272,3274,3276,3278,3280,3282,3284,3286,3289,3291],{"class":209,"line":341},[207,3273,1917],{"class":217},[207,3275,277],{"class":227},[207,3277,231],{"class":360},[207,3279,262],{"class":227},[207,3281,434],{"class":360},[207,3283,228],{"class":227},[207,3285,280],{"class":227},[207,3287,3288],{"class":283},"tasks",[207,3290,444],{"class":227},[207,3292,368],{"class":227},[207,3294,3295],{"class":209,"line":371},[207,3296,3297],{"class":457},"# IDs in quests_objects and tasks_objects are independent\n",[207,3299,3300],{"class":209,"line":390},[207,3301,3302],{"class":457},"# — a quest with id=1 and an unrelated object with id=1\n",[207,3304,3305],{"class":209,"line":404},[207,3306,3307],{"class":457},"#    in another collection could create false matches\n",[3309,3310,3311,3312,3316],"callout",{"icon":14},"See ",[1501,3313,3315],{"href":3314},"/essentials/collections#choosing-a-collection-name","Choosing a collection name"," for guidance on when separate collections make sense — but never split parent-child models across them.",[125,3318,3320],{"id":3319},"async-support","Async support",[112,3322,3323,3324,193,3327,296],{},"All relation methods are available on ",[116,3325,3326],{},"AsyncCollection",[116,3328,3329],{},"AsyncTimeSeriesCollection",[198,3331,3333],{"className":200,"code":3332,"language":202,"meta":203,"style":203},"from centaurodb import AsyncCollection, Engine\n\nengine = Engine(\":memory:\", check_same_thread=False)\ncoll = AsyncCollection(engine, \"quests\")\n\nawait coll.write_object(quest)\nawait coll.write_child(task, parent=quest)\ntasks = await coll.children_of(quest, Task)\n",[116,3334,3335,3351,3355,3380,3402,3406,3423,3447],{"__ignoreMap":203},[207,3336,3337,3339,3341,3343,3346,3348],{"class":209,"line":210},[207,3338,214],{"class":213},[207,3340,218],{"class":217},[207,3342,221],{"class":213},[207,3344,3345],{"class":217}," AsyncCollection",[207,3347,228],{"class":227},[207,3349,3350],{"class":217}," Engine\n",[207,3352,3353],{"class":209,"line":244},[207,3354,248],{"emptyLinePlaceholder":247},[207,3356,3357,3359,3361,3363,3365,3367,3370,3372,3374,3377],{"class":209,"line":251},[207,3358,412],{"class":217},[207,3360,277],{"class":227},[207,3362,224],{"class":360},[207,3364,262],{"class":227},[207,3366,444],{"class":227},[207,3368,3369],{"class":283},":memory:",[207,3371,444],{"class":227},[207,3373,228],{"class":227},[207,3375,3376],{"class":473}," check_same_thread",[207,3378,3379],{"class":227},"=False)\n",[207,3381,3382,3384,3386,3388,3390,3392,3394,3396,3398,3400],{"class":209,"line":271},[207,3383,425],{"class":217},[207,3385,277],{"class":227},[207,3387,3345],{"class":360},[207,3389,262],{"class":227},[207,3391,434],{"class":360},[207,3393,228],{"class":227},[207,3395,280],{"class":227},[207,3397,1580],{"class":283},[207,3399,444],{"class":227},[207,3401,368],{"class":227},[207,3403,3404],{"class":209,"line":290},[207,3405,248],{"emptyLinePlaceholder":247},[207,3407,3408,3411,3413,3415,3417,3419,3421],{"class":209,"line":308},[207,3409,3410],{"class":213},"await",[207,3412,687],{"class":217},[207,3414,494],{"class":227},[207,3416,497],{"class":360},[207,3418,262],{"class":227},[207,3420,1625],{"class":360},[207,3422,368],{"class":227},[207,3424,3425,3427,3429,3431,3433,3435,3437,3439,3441,3443,3445],{"class":209,"line":313},[207,3426,3410],{"class":213},[207,3428,687],{"class":217},[207,3430,494],{"class":227},[207,3432,525],{"class":360},[207,3434,262],{"class":227},[207,3436,1680],{"class":360},[207,3438,228],{"class":227},[207,3440,562],{"class":473},[207,3442,277],{"class":227},[207,3444,1625],{"class":360},[207,3446,368],{"class":227},[207,3448,3449,3451,3453,3456,3458,3460,3462,3464,3466,3468,3470],{"class":209,"line":327},[207,3450,1917],{"class":217},[207,3452,277],{"class":227},[207,3454,3455],{"class":213}," await",[207,3457,687],{"class":217},[207,3459,494],{"class":227},[207,3461,163],{"class":360},[207,3463,262],{"class":227},[207,3465,1625],{"class":360},[207,3467,228],{"class":227},[207,3469,1331],{"class":360},[207,3471,368],{"class":227},[112,3473,3474,3475,3478],{},"See the ",[1501,3476,3477],{"href":70},"Async guide"," for setup and usage patterns.",[3480,3481,3482],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":203,"searchDepth":244,"depth":244,"links":3484},[3485,3492,3493,3498,3504,3505,3506,3507,3508,3509,3510],{"id":127,"depth":244,"text":3486,"children":3487},"parent_ref vs nested models",[3488,3490,3491],{"id":137,"depth":251,"text":3489},"Use parent_ref when:",{"id":761,"depth":251,"text":762},{"id":1188,"depth":251,"text":1189},{"id":1237,"depth":244,"text":1238},{"id":1514,"depth":244,"text":1515,"children":3494},[3495,3496],{"id":1521,"depth":251,"text":1522},{"id":1771,"depth":251,"text":3497},"Approach 2: One-step with write_child",{"id":1897,"depth":244,"text":1898,"children":3499},[3500,3502],{"id":1901,"depth":251,"text":3501},"Using children_of",{"id":2027,"depth":251,"text":3503},"Using read_objects with conditions",{"id":2277,"depth":244,"text":2278},{"id":2351,"depth":244,"text":1504},{"id":2477,"depth":244,"text":2478},{"id":2628,"depth":244,"text":2629},{"id":2959,"depth":244,"text":2960},{"id":3124,"depth":244,"text":3125},{"id":3319,"depth":244,"text":3320},"Link parent and child objects with parent_ref — build one-to-many relationships without foreign key migrations.","md",null,{},{"icon":56},{"title":53,"description":3511},"iiYtuPMxgumz-9VEJUtdxtEaBLI8fcVTnn4XrVQ4E08",[3519,3521],{"title":48,"path":49,"stem":50,"description":3520,"icon":51,"children":-1},"Add, remove, and rename fields without migrations — just update your Python class and redeploy.",{"title":64,"path":65,"stem":66,"description":3522,"icon":67,"children":-1},"Store and query time-series data with TimeSeriesCollection, Polars DataFrames, and flexible update modes.",1781105062343]