MomentoがList・Set・Dictionaryデータ型をサポートしました

2023.01.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Introduction

高速サーバレスキャッシュサービスMomentoの情報です。
いままではbyte最近のアップデートにより、コレクションデータ型がサポートされました。
今回はMomentoのJavaScript用SDKを使って
コレクション型をつかったMomentoへのアクセスを試してみます。

※ DevIOのMomento関連記事はこちら

Environment

今回試した環境は以下のとおりです。

  • MacBook Pro (13-inch, M1, 2020)
  • OS : MacOS 12.4
  • Node : v18.2.0

Setup

まずはMomentoのセットアップです。
このあたりを参考に、
Momentoの認証トークンを取得しましょう。

トークンを取得したらコンソールで環境変数にセットしておきます。

% export MOMENTO_AUTH_TOKEN = <取得した認証トークン>

必要なモジュールをnpmでインストールします。
今回のサンプルではTypeScriptを使うのでts-nodeもインストールしておきます。

% npm install --save typescript ts-node @gomomento/sdk

Try

ではMomentoでコレクションをつかってみましょう。
まずは必要モジュールのimportとクライアントの作成です。

//main.ts
import {
  CacheGet,
  ListCaches,
  CreateCache,
  CacheSet,
  CacheDelete,
  DeleteCache,
  LogLevel,
  LogFormat,
  SimpleCacheClient,
  EnvMomentoTokenProvider,
  Configurations,
  LoggerOptions,
  CollectionTtl,
  CacheListFetch,
  CacheSetFetch,
  CacheDictionarySetField,
  CacheDictionaryGetField,
  CacheDictionaryGetFields,
} from '@gomomento/sdk';


const cacheName = 'my_cache';

const credentialsProvider = new EnvMomentoTokenProvider('MOMENTO_AUTH_TOKEN');

const loggerOptions: LoggerOptions = {
  level: LogLevel.INFO,
  format: LogFormat.JSON,
};

const defaultTtl = 60;
const momento = new SimpleCacheClient({
  configuration: Configurations.Laptop.latest(loggerOptions),
  credentialProvider: credentialsProvider,
  defaultTtlSeconds: defaultTtl,
});

const main = async () => {
  //サンプルで使用するキャッシュの作成
  const createCacheResponse = await momento.createCache(cacheName);
  if (createCacheResponse instanceof CreateCache.AlreadyExists) {
    console.log('cache already exists');
  } else if (createCacheResponse instanceof CreateCache.Error) {
    throw createCacheResponse.innerException();
  }

   /*************************
   /* ここにコードを追記していく
   **************************/


  //作成したキャッシュを削除
  const deleteResponse = await momento.deleteCache(cacheName);
  if (deleteResponse instanceof DeleteCache.Error) {
    console.log(`Error deleting cache key: ${deleteResponse.toString()}`);
  } else if (deleteResponse instanceof DeleteCache.Success) {
    console.log('Delete cache');
  }

};

main()
  .then(() => {
    console.log('ok');
  })
  .catch(e => {
    console.error('error occured : ', e);
  });

キャッシュの作成と削除を記述し、
その間に各種コードを記述していきます。
既存(コレクションへのアクセス機能追加前)のキャッシュをそのまま使おうとすると
↓みたいなエラーが出るかもしれないので注意してください。

Error {
  _innerException: TimeoutError: 4 DEADLINE_EXCEEDED: undefined

・・・

      at processTicksAndRejections (node:internal/process/task_queues:95:5) {
    _transportDetails: MomentoErrorTransportDetails { grpc: [MomentoGrpcErrorDetails] },
    _errorCode: 'TIMEOUT_ERROR',
    _messageWrapper: "The client's configured timeout was exceeded; you may need to use a Configuration with more lenient timeouts"

List

まずはListをつかってみます。
基本的にキャッシュ名とリスト名を指定して値を追加したり削除したりします。

  const listName:string = "MyList";
  const values:string[] = ['one', 'two', 'three','four'];

  //リストに値を追加
  let resp1 = await momento.listConcatenateFront(cacheName,listName,values);
  console.log("======= listConcatenateFront =======");
  console.log(resp1); //[ 'one', 'two', 'three', 'four' ]

  //リストの長さを取得
  console.log("======= listLength =======");
  const resp2 = await momento.listLength(cacheName, listName);
  console.log(resp2); // _list_length: 4

  //リストを取得
  console.log("======= listFetch =======");
  const resp3 = await momento.listFetch(cacheName, listName);
  if (resp3 instanceof CacheListFetch.Hit) {
    //Listから配列に変換
    const valuesList = resp3.valueListString();
    const array = [...valuesList];
    console.log(array); //[ 'one', 'two', 'three', 'four' ]
  } 


  //リストの後ろから値をpop
  console.log("======= listPopBack =======");
  const resp4 = await momento.listPopBack(cacheName, listName);
  if (resp4 instanceof CacheGet.Hit) {
    console.log(resp4.valueString()); //four
  } 

  //リスト前から値をpop
  console.log("======= listPopFront =======");
  const resp5 = await momento.listPopFront(cacheName, listName);
  if (resp5 instanceof CacheGet.Hit) {
    console.log(resp5.valueString()); //one

  } 
 
  //リストの後ろに値を追加
  console.log("======= listPushBack =======");
  await momento.listPushBack(cacheName, listName,"five");
 
  //リストの前に値を追加
  console.log("======= listPushFront =======");
  await momento.listPushFront(cacheName, listName,"zero");

  //リストから値を削除
  console.log("======= listRemoveValue =======");
  await momento.listRemoveValue(cacheName, listName,"three");

  // List  = [ 'zero', 'two', 'five' ]

listPushFront/listPushBackでリストへの追加、
listPopFront/listPopBackでリストから取り出しです。
listFetchでリスト全体の取得になります。

Set

Setの使い方はListとだいたい同じです。

  let setName = "MySet";
  
  //Setへ要素の追加
  console.log("======= setAddElement =======");
  await momento.setAddElement(cacheName, setName,"hello"); 
  //[ 'hello']

  //Setへ要素を複数追加
  console.log("======= setAddElements =======");
  await momento.setAddElements(cacheName, setName,["hi","bye"]);
  //["hello","hi","bye"]

  //Setから要素の削除
  console.log("======= setRemoveElement =======");
  await momento.setRemoveElement(cacheName, setName,"hi");
  //["hello","bye"]

  //Set取得
  console.log("======= setFetch =======");
  const rest_set = await momento.setFetch(cacheName, setName);
  if (rest_set instanceof CacheSetFetch.Hit) {
    //Setから配列に変換
    const valuesSet = rest_set.valueSetString();
    const array = [...valuesSet];
    console.log(array);
  }

Dictionary

次はDictionaryを使ってみます。
この場合も、コレクションの名前を指定して
操作するという部分については同じです。

  let dictionary = [ 
    { field : 'nakamura', value:'shuta'},
    { field : 'cm', value:'taro'},
    { field : 'count1', value:"10"},
    { field : 'count2', value:"20"},
  ];
  

  let dictName = "MyDict";
  //Dictionaryに値を追加
  console.log("======= dictionarySetField =======");
  await momento.dictionarySetField(cacheName, dictName,'key-dictionary','vakue-dictionary');

  //dictionary変数をDictionaryに追加
  //Set several dictionary field-value pairs in the cache.
  console.log("======= dictionarySetFields =======");
  await momento.dictionarySetFields(cacheName, dictName,dictionary);

  //Dictionaryにキーを指定して値を取得
  console.log("======= dictionaryGetField =======");
  const dict_resp = await momento.dictionaryGetField(cacheName, dictName,"nakamura");
  if (dict_resp instanceof CacheDictionaryGetField.Hit) {
    console.log(dict_resp.valueString()); // shuta
  } 

  //Dictionaryに複数キーを指定して値を取得
  console.log("======= dictionaryGetFields =======");
  const dict_resp2 = await momento.dictionaryGetFields(cacheName, dictName,["nakamura","cm"]);
  if (dict_resp2 instanceof CacheDictionaryGetFields.Hit) {
    let map = dict_resp2.valueDictionaryStringString();
    console.log(map.get("nakamura")); //shuta
    console.log(map.get("cm")); //taro
  } 

  //数値をインクリメント
  console.log("======= dictionaryIncrement =======");
  await momento.dictionaryIncrement(cacheName, dictName,"count1"); // count1 -> 11

  //Dictionaryから値を削除
  console.log("======= dictionaryRemoveField =======");
  await momento.dictionaryRemoveField(cacheName, dictName,"nakamura");

  //Dictionaryから複数の値を削除
  console.log("======= dictionaryRemoveFields =======");
  await momento.dictionaryRemoveFields(cacheName, dictName,["cm","count1"]);

  //Dictionnary一覧取得
  console.log("======= dictionaryFetch =======");
  await momento.dictionaryFetch(cacheName, dictName);

なお、dictionaryIncrementを使う場合、
vakueがStringかつ数値としてパースできるフォーマットである必要があります。

Summary

今回はTypeScriptでMomentoのコレクション操作をしてみました。
通常のコレクションと同じように簡単に操作できますね。

使える関数はsimple-cache-client.d.tsを見ればわかるので、
確認してみてください。

この記事でキャッシュに使用したMomentoについてのお問い合わせはこちらです。
お気軽にお問い合わせください。

Momentoセミナーのお知らせ

2023年2月21日(火) 16:00からMomentoのセミナーを開催します。
興味があるかたはぜひご参加ください。