ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

リレーションデータの作成順番について

f:id:mbaasdevrel:20180913163950p:plain

データストアでは多対多の関係性を表現するのにリレーション機能が使えます。あるデータに紐付く多数のデータを管理します。

そんなリレーションはデータ作成時にも使えるのですが、mBaaSにはトランザクションがないので使い方に注意する必要があります。

実装例

例えば以下のような実装があります。ParentのデータがChildのデータを3件リレーションで連結しています。注意点として、child2だけ .set('date', new Date(undefined)) をしています。これは不正な日付なのでデータ保存時にエラーを起こします。

const Parent = ncmb.DataStore('Parent');
const Child = ncmb.DataStore('Child');

(async () => {
  const parent = new Parent;
  const relation = new ncmb.Relation();
  const child1 = new Child;
  const child2 = new Child;
  const child3 = new Child;

  child1.set('name', '子要素1');
  child2.set('name', '子要素2').set('date', new Date(undefined));
  child3.set('name', '子要素3');

  relation.add(child1).add(child2).add(child3);
  parent.set('children', relation);
  await parent.save();
  console.log(parent);
})();

この状態で保存するとどうなるでしょうか。

リレーションデータの保存について

この保存処理では、まずリレーションに結びつけられているデータから保存されます。つまり child1〜child3 が最初に保存されます。注意して欲しいのは、保存順番はネットワークの状態によってバラバラに行われると言うことです。試してみた限りではchild3、つまり最後に登録されたデータから保存されるようです。ただし非同期です。

そしてchild2でエラーが起きた時点で処理が停止します。この時、parentは保存されていません。かといってchild3は(場合によってはchild1も)保存された状態になっています。child1〜child3が保存された後、parentが保存されます。もしparentの保存に失敗した場合はchild1〜child3が残された状態になります。

データの状態について

もしデータが正常に保存された場合、parentとchild1〜child3は次のようになっています。

Data {
  createDate: '2019-10-18T06:17:10.096Z',
  objectId: '9ytyhNENNUyZwS6o' }
Data {
  name: '子要素1',
  createDate: '2019-10-18T06:17:09.954Z',
  objectId: 'lc0ozCokrYKHmU3' }
Data {
  name: '子要素2',
  createDate: '2019-10-18T06:17:09.955Z',
  objectId: 'lL6oJ7NrCXlujVhn' }
Data {
  name: '子要素3',
  createDate: '2019-10-18T06:17:09.952Z',
  objectId: 'tiPqMTfG2WXwyRS' }

しかし1件でも保存に失敗すると次のようになります。parentが保存されていないのは良いのですが、child1〜child3のいずれかは保存されているにも関わらずobjectIdが入っていないので注意してください。

Data {
  children:
   Relation {
     __op: 'AddRelation',
     objects:
      [ Data { name: '子要素1' },
        Data { name: '子要素2', date: { __type: 'Date', iso: null } },
        Data { name: '子要素3' } ],
     relatingClass: '/classes/Child' } }
Data { name: '子要素1' }
Data { name: '子要素2', date: { __type: 'Date', iso: null } }
Data { name: '子要素3' }

まとめ

リレーションの保存はデータを一括で送信している訳ではないので、個別にデータ保存を行った方が安全に見えます。特にどのデータが保存に失敗したか分からない状態なのはデータ管理上、問題になるかも知れません。実装時にはご注意ください。

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。