Monday, November 21, 2016

Rethinkdb replace multiple fields with object and array as nested field type

I came across a requirement where I need to replace multiple fields in a document. In my case the document has two fields, one as object and other as array. What was needed is modify the nested array and object in the same query.

Let’s take an example document for this case-
{
 "badgeCount" : {
  "09cf79ad-cce7-4826-8a66-e0653eabae4e" : 0,
  "5cdf9a50-b4e3-4240-8ddc-979b25820745" : 1
 },
 "createdDate" : new Date(),
 "deleted" : false,
 "roomName" : "my room",
 "description" : "my room description",
 "id" : "c58f3c08-4d84-41c7-b705-88cd081dfa04",
 "joinedUserIds" : [
  "09cf79ad-cce7-4826-8a66-e0653eabae4e",
  "5cdf9a50-b4e3-4240-8ddc-979b25820745"
 ]
}
This document is about a room, where a user can join a room via joinedUserIds and they have badgeCount which says how many new messages are there in the room. Each item in the array joinedUserIds is a use id and there is a property of the same user id in the badgeCount object.

So, in my case what was needed, when a user leaves a room we need to remove the user id from joinedUserIds and also from badgeCount.

Solution goes like this-
r.db('test').table('room').get("c58f3c08-4d84-41c7-b705-88cd081dfa04").replace(function (s) {
 return s.without({
  badgeCount : {
   "09cf79ad-cce7-4826-8a66-e0653eabae4e" : true
  }
 }).without("joinedUserIds").merge({
  joinedUserIds : s("joinedUserIds").filter(function (id) {
   return id.ne("09cf79ad-cce7-4826-8a66-e0653eabae4e");
  })
 })
})
We have solved this by replace with chained without. First without is removing 09cf79ad-cce7-4826-8a66-e0653eabae4e from badgCount. Result of first without is, it will remove 09cf79ad-cce7-4826-8a66-e0653eabae4e from badgeCount object. Second without removes joinedUserIds and then adds it back with merge and filter.