JSONのキーをIDにする話

昔所属していたプロジェクトではAの形式を使っていました。これは以下のような事情があったためです

  • データストアにmongoDBを使用
  • mongooseなどのライブラリを使わず、mongoドライバを直接使用
  • バックエンド、フロント共にJSなので、JSONオブジェクトのキーがIDでも柔軟に対応可能
  • アプリケーションの性質上、ほぼID指定でのオペレーション
  • 順番は重要でない
  • countの値の整合性が重要

このアプリケーション、ゲームなんですけど、ゲームなのでユーザはアイテムを持ってます。そのデータは

{
  _id: <user-id-1> 
  items: {
    <item-id-1>: { count: 1 }, 
    <item-id-2>: { count: 2 },
  }
}

という形式のドキュメントでmongoDBに保存されていました。この形式で <item-id-1>の所持数を1つ増やそうとすると

collection.updateOne({_id: <user-id-1>}, {$inc: {"items.<item-id-1>.count" : 1}}, {upsert: true})

とかけます(もし指定のフィールドがなかった場合、count: 1で自動的に作られます)

Bの形式で保存する場合

{
  _id: <user-id-1> 
  items: [
    { id: <item-id-1>,  count: 1 }, 
    { id: <item-id-2>,  count: 2 },
  ]
}

となりますが、<item-id-1>のcountを$incで増減する方法がありません。$push, $pullを用いてitems配列の1つの要素をまるっと置き換える必要があります。

しかし、それは値の安全性や性能面で不利になります。$incは複数のプロセスから書き込まれても楽観ロックさえも必要なく安全に増減できるという大きな利点があるのです。このアプリケーションは1秒間に5万近いクエリが走る非常に負荷の高いものだったため、ロック不要というのは性能面でも大きなメリットとなりました。

ま、とはいえ、そんな事情でもなければ今ならAの形式は選ばないと思います。適切な型をつけるのが難しいのでTypeScriptなどと相性が悪そうなので・・・

ところでAってモダンでスタンダードなんですかね?2011年に始まったプロジェクトの話なのでモダンというイメージはもう無いんですが・・・