Mongo에 내장 함수를 만들 수 있다고해서 테스트 해 봤다. mongo 쉘에서 테스트해보니 잘 된다. 아마도 nodejs에서는 이 js function을 호출할 수 있는 라이브러리가 있을 것 같다. deno에 mongodb 라이브러리인 https://deno.land/x/mongo 에서는 아직 호출 기능을 제공하지 않는다. mongodb는 trigger도 단독 서버에서는 지원하지 않는다. 관계형 db에서는 trigger를 유용하게 사용했었는데 아쉽다.
getNextTS 는 moneyBookId를 별로 sequence 를 증가시켜서 리턴하는 함수다.
> db.MoneyBook.insertOne({name:"Money book1"})
{
"acknowledged" : true,
"insertedId" : ObjectId("610654e943cca4c015817161")
}
> db.MoneyBook.find()
{ "_id" : ObjectId("610654e943cca4c015817161"), "name" : "Money book1" }
> db.TSList.insertOne({moneyBookId: ObjectId("610654e943cca4c015817161"), collectionName: "transfer", ts: 1})
{
"acknowledged" : true,
"insertedId" : ObjectId("6106555d43cca4c015817162")
}
> db.TSList.find()
{ "_id" : ObjectId("6106555d43cca4c015817162"), "moneyBookId" : ObjectId("610654e943cca4c015817161"), "collectionName" : "transfer", "ts" : 1 }
# 함수 저장
db.system.js.remove({_id: 'getNextTS'})
db.system.js.insertOne(
{
_id : 'getNextTS',
value : function(moneyBookId, collectionName) {
var ret = db.TSList.findAndModify( { query: {moneyBookId: moneyBookId, collectionName: collectionName}, update: {$inc: {ts: 1} }, new: true } );
return ret.ts;
}
}
)
> db.loadServerScripts()
> getNextTS(ObjectId("610654e943cca4c015817161"), "transfer")
4
Client 앱의 관계형 db의 id는 integer형으로 AUTOINCREMENT 를 이용하면 손쉽게 사용할 수 있다. Mongodb의 id는 이런 형태가 아니기 때문에 코드 구현으로 생성해 주는 방법이 필요하다. client에도 server id를 저장할 필요가 있어서, type을 Int로 맞출필요가 있다.
// collectin name
export const kNextId = "next_id"
// id auto increment
export interface INextId {
did: number
cid: number,
id: number
}
import { Bson, MongoClient } from "https://deno.land/x/mongo/mod.ts"
class MyMongoClient {
dbName: string
url: string
client: MongoClient
constructor(dbName: string, url: string) {
this.dbName = dbName;
this.url = url;
this.client = {} as MongoClient;
}
async connect() {
console.log("mongodb connecting ...")
const client = new MongoClient();
await client.connect(this.url);
this.client = client;
console.log("mongodb connected OK")
}
getDatabase() {
return this.client.database(this.dbName);
}
}
export const mongoClient = new MyMongoClient("testdb", "mongodb://127.0.0.1:27017")
await mongoClient.connect()
const db = mongoClient.getDatabase()
const nextIdCollection = db.collection<INextId>(kNextId)
export async function getNextId(cid: number, did: number) : Promise<INextId | undefined> {
return await nextIdCollection.findAndModify(
{cid: cid, did: did},
{
update: { $inc: { id: 1 } },
new: true,
upsert: true
}
)
}
이렇게 사용한다. 서버에는 사용자 별로 did가 생성되는데, 특정 collection에 특정 did 별로 sequence를 발급하는 함수를 직접 호출해서 구하고, insert 하기 전에 그 값을 사용하도록 한다.
const aid = (await getNextId(kCidAccount, did))!.id