Článek přečtěte do 6 min.

MongoDB nedávno přidal nového operátora $sql do svého agregačního potrubí (od konce února 2024 je v současné době stále v beta verzi), takže jsme v Oracle usoudili, hej, máme také SQL ;-). Ale na rozdíl od nich se SQL zabývají už nějakou dobu, tak proč tohoto operátora nepodpořit a nenabídnout našim zákazníkům svět výkonného SQL Oracle v rámci MongoDB API? Přesně to co udělali.

Používejte Oracle SQL s Oracle MongoDB API a okamžitě těžte z konvergované databáze Oracle. 

K čemu to mohu použít?

  • Máte data v klasických relačních tabulkách, která chcete sdílet jako kolekci v aplikaci MongoDB? Pokryli vás.
  • Máte data v klasických relačních tabulkách, která chcete kombinovat a zpracovávat společně s kolekcemi ve vaší aplikaci MongoDB? Pokryli vás.
  • Chcete využít některé pokročilé funkce SQL, které je těžké nebo nemožné udělat v MongoDB? Pokryli vás.
  • Máte nějakou procedurální logiku, kterou chcete integrovat do agregačního potrubí? Pokryli vás.
  • Potřebujete pragmatický a přímočarý způsob, jak se vypořádat se stále ubývajícími maličkostmi, které jsme nestihli implementovat, aniž bychom opustili ekosystém Mongo? Tím vás také zabavili.

Ano, používáte Oracle SQL, aniž byste opustili svět MongoDB API a integrovali a pracovali společně s relačními daty a kolekcemi MongoDB vedle sebe.

Rychlá procházka

Dovolte nám, abychom vám dali několik jednoduchých příkladů, abyste měli představu o tom, co je zde proveditelné. Následují jednoduché mongosh příklady pro ilustraci, ale netřeba říkat, že jakákoli integrace – jako použití proměnných vazby – může být plně zabudována do vaší aplikace.

Vystavte relační data

Předpokládejme, že jednoduše chcete vystavit data pocházející z vašeho relačního základního systému jako kolekci pouze pro čtení, aniž byste data přetrvávali a pravidelně aktualizovali jako kolekci Mongo. Není třeba kopírovat nebo přenášet data: stačí vybrat informace dynamicky pomocí SQL z čistých relačních struktur a vložit je do aplikace.

db.aggregate([{$sql: `
             select fiscal_year, fiscal_quarter_number, sum(amount_sold) as sum_amount
             from sh.times t join sh.sales s on (t.time_id = s.time_id)
             group by fiscal_year, fiscal_quarter_number order by 1,2`}
])

V reálném světě je to často zasazeno do kontextu aplikace a předchozích filtrů a hodnot, takže pojďme použít proměnné vazby k omezení sady výsledků ve vaší aplikaci. Použití vazeb stejně jako v JDBC pomáhá zlepšit výkon a zabraňuje jakémukoli typu SQL injection:

db.aggregate([ {$sql: 
                  { statement: ` 
                      select 
                         fiscal_year, fiscal_quarter_number, sum(amount_sold) as sum_amount 
                      from sh.times t join sh.sales s on (t.time_id = s.time_id) 
                      where fiscal_year = :1 
                      group by fiscal_year, fiscal_quarter_number 
                      order by 1,2`, 
                    binds: [
                        { index: 1, value: 2019}
                        ]
                    }}
])

To funguje dobře v jakékoli databázi Oracle 19c a vyšší, v místním prostředí a s autonomní databází.

Jednoduché vyhledávání s relačními daty

Udělejme věci trochu zajímavějšími: provozujete svou aplikaci Mongo pro konkrétní obchodní jednotku, která chce nyní rozšířit své kolekce o data z běžných podnikových entit uložená centrálně ve vaší podnikové databázi. Můžete tak učinit pomocí jednoduchého „vyhledání $sql“ – připojte se k relačnímu žargonu – a přidejte tolik dalších společných atributů, kolik chcete. V rámci agregačního kanálu používáte $sql stejně jako kterákoli jiná fáze, která spotřebovává vstupní dokumenty z předchozí fáze a vytváří dokumenty pro následující fáze.

Nejprve analyzujme JSON naši tabulku EMP a považme ji za naši kolekci dokumentů (nazýváme ji empJSON) s referenčním modelem propojeným s naší čistě relační tabulkou DEPT. Chceme vystavit informace o našich zaměstnancích (kromě mzdy) v jednoduché webové aplikaci. K tomu použijeme mongosh:

jason> db.aggregate([{$sql:`
                         select json{empno, ename, job, mgr, hiredate, deptno} from emp`
                      },
...                   {$out: "empJSON"}])

jason> db.empJSON.findOne()
{
  _id: ObjectId('65ea34720af5351d8f7bf901'),
  empno: 7839,
  ename: 'KING',
  job: 'PRESIDENT',
  mgr: null,
  hiredate: ISODate('1981-11-17T00:00:00.000Z'),
  deptno: 10
}

To nebylo příliš těžké, že?

V aplikaci však nechceme zobrazovat číslo oddělení, ale název oddělení. A z nějakého důvodu nechceme uchovat název oddělení v naší uložené sbírce. Pojďme to tedy vyhledat v reálném čase pomocí fáze $sql, kdykoli potřebujeme výsledek, a spojte naši sbírku s naší čistě relační tabulkou.

jason> db.empJSON.aggregate([{$sql: `
                                select json_transform(e.data, set '$.dname' = d.dname, remove '$.deptno') 
                                from input e, dept d 
                                where e.data.deptno.number() = d.deptno`
                               },
...                            {$limit: 1}])
[
  {
    _id: ObjectId('65ea34720af5351d8f7bf901'),
    empno: 7839,
    ename: 'KING',
    job: 'PRESIDENT',
    mgr: null,
    hiredate: ISODate('1981-11-17T00:00:00.000Z'),
    dname: 'ACCOUNTING'
  }
]

V tomto malém příkladu vidíte, jak transparentně integrovali fázi $sql do agregačního kanálu Mongo: kolekce vytvořené předchozími fázemi jsou reprezentovány jako INPUT kolekce JSON s jediným sloupcem DATA obsahující vaše dokumenty. Jednoduše jsme spojili naši kolekci empJSON s relační tabulkou DEPT, přidali pole ‚dname‘ a odstranili zbytečné pole ‚deptno‘. Mise splněna, EMP a DEPT jsou nyní oficiálně součástí ukázek MongoDB.

Použití agregačního kanálu tímto způsobem vyžaduje Oracle Database 23c.

Využijte analýzy a zapouzdřenou obchodní logiku

Takže jste stejně důvtipní v SQL jako v žargonu MongoDB? Vyberte si, co umíte nejlépe a nejrychleji. Následuje poměrně jednoduchý příklad, který agreguje a seřadí váš roční hrubý příjem s filmy pomocí SQL, třídí data a dává nám klíčové atributy pro prvních deset.

db.movies.aggregate([
          {$match: {year:2019, gross : {$ne: null}}},
          {$sql:`
              select json_mergepatch(i.data, json {'rank': rank() over (order by i.data."gross" desc)})
              from input i`},
          {$project: { rank: 1, year: 1, title: 1, gross: 1, "_id": 0 }},
          {$match: {rank : {$le : 10}}},
          {$sort: {rank: 1}}
])

V tomto jednoduchém příkladu provádíme hodnocení v SQL, ale třídění a omezení na prvních deset v agregačním kanálu, jen abychom ukázali zaměnitelnost. Mohli udělat všechno v SQL (nebo v agregačním kanálu Mongo, když na to přijde), ale rozhodli se provést hodnocení (a implicitně požadované třídění) pouze v Oracle, takže funkce podnikového výkonu Oracle mohou volně procházet daty.

Finanční oddělení pracovalo na magické globální finanční hrubé úpravě, která se používá všude a je zapouzdřena v SQL. Co teď? No, stačí přidat fázi potrubí a použít kouzlo na svou sbírku Mongo, vypočítat správné číslo a přidat upravený hrubý příjem do své sbírky:

db.movies.aggregate([{$sql: `
                      select json_mergepatch(i.data,
                             json{'adjGross':adjust_gross(i.data.gross.number())})
                      from input i, dual`}
])

Překlenout mezery

V neposlední řadě můžete SQL použít na vše, co Oracle MongoDB API nepodporuje. Jak již bylo krátce zmíněno, naší vizí a cílem není být Me-Too Mongo. Naší vizí je podnik a úplnost konvergované databáze, která podporuje jakýkoli datový typ s jakoukoli pracovní zátěží. S největší pravděpodobností budou vždy existovat mezery ve funkčnosti, dokud budou existovat MongoDB a Oracle.

Jednou z nejvýraznějších nedostatků k dnešnímu dni je chybějící vytváření indexů prostřednictvím MongoDB API v Oracle Database 19c. Před operátorem $sql jste museli opustit eko systém MongoDB, připojit se k nástroji SQL a vytvořit libovolný index odtud. Se zavedením operátoru $sql stále používáte SQL, ale není třeba opouštět eko systém MongoDB. Stačí použít operátor $sql v Oracle Database 19c a tuto mezeru prozatím pragmaticky překlenout, dokud nebude Oracle Database 23c na vašem radaru. Oracle Database 23c podporuje vytváření indexů prostřednictvím MongoDB API, ale předtím – jako v Autonomous Database – přichází na pomoc naše fáze $sql .

db.aggregate([{ $sql: `
                create index i_movies_sku
                on movies(json_value(data, '$.sku.stringOnly()' ERROR ON ERROR))`}
])

Úspěšné vytvoření indexu uvidíte hned poté:

jason> db.movies.getIndexes()
[
  {
    name: 'I_MOVIES_SKU',
    indexNulls: false,
    unique: false,
    v: 2,
    key: { 'sku.stringOnly()': 1 },
    ns: 'jason.movies'
  },
  { v: 2, key: { _id: 1 }, ns: 'jason.movies', name: '_id_' }

]

Podívejte se na index v práci:

jason> db.movies.find({"sku":"NTV55017"}).explain()
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'jason.movies',
    indexFilterSet: false,
    parsedQuery: { sku: { '$stringOnly': 'NTV55017' } },
    rewrittenQuery: { sku: { '$stringOnly': 'NTV55017' } },
    winningPlan: {
      stage: 'SELECT STATEMENT',
      inputStage: {
        stage: 'TABLE ACCESS',
        options: 'BY INDEX ROWID BATCHED',
        source: 'MOVIES',
        columns: '"MOVIES"."ID"[RAW,4000], "CREATED_ON"[TIMESTAMP,11], "LAST_MODIFIED"[TIMESTAMP,11], "VERSION"[VARCHAR2,255], "DATA" /*+ LOB_BY_VALUE */ [JSON,8200]',
        inputStage: {
          stage: 'INDEX',
          options: 'RANGE SCAN',
          source: 'I_MOVIES_SKU',
          columns: `"MOVIES".ROWID[ROWID,10], JSON_VALUE("DATA" /*+ LOB_BY_VALUE */  FORMAT OSON , '$.sku.stringOnly()' RETURNING VARCHAR2(4000) ERROR ON ERROR)[VARCHAR2,4000]`,
          filterType: 'access',
          filter: `JSON_VALUE("DATA" /*+ LOB_BY_VALUE */  FORMAT OSON , '$.sku.stringOnly()' RETURNING VARCHAR2(4000) ERROR ON ERROR)=:1`,
          path: "$.sku.stringOnly()'"
        }
      }
    },
    rejectPlans: []
  },
  serverInfo: { host: 'localhost', port: 27017, version: '4.2.14' },
  ok: 1
}

To je docela seznam skvělých věcí, které teď můžete dělat, ne?

Závěr

Pokud *používáte* Oracle kdekoli ve vašem podniku nebo si představujete použití svých dat pro více než jednu aplikaci nebo předmět, přemýšlejte o výhodách konvergované databáze pro vaši společnost. Naší vizí je, že by neměly existovat žádné hranice nebo datová sila „jen proto“. Ve společnosti Oracle vám dávají na výběr a nejlepší možné prostředky k řešení všech vašich obchodních požadavků pomocí nejlepších možných nástrojů a dostupných jazyků. S jednou databází.

Nejde o MongoDB API versus SQL; je to o výběru a mít vše v jednom rámci. A brzy přibudou další… .

O této nové fázi agregačního kanálu si můžete přečíst v dokumentaci Oracle. Přesvědčte se sami, máme pro vás dostatek LiveLabů zdarma. Ať už jde o zkušenost s plně spravovanou databázovou službou Autonomous JSON, nebo o hru s nejnovější a nejlepší, Oracle Database 23c  s agregačním kanálem, která brzy přijde na Autonomous.

Šťastné kódování. Dejte nám vědět, co si myslíte.

Zdroj: Oracle