David Panart
David Panart

Reputation: 656

Handling a user activity feed with mongoDB

I have a activityFeeds collection where each document's primary key is the same _id as the user's _id it refer to.

I did a getTimeKey function that return a string according to a specific date

/*
** Return a string like 1_2015 for january 2015
** If timestamp is not defined, current date is used
*/
getTimeKey = function (timestamp)
{
    var date = (timestamp === undefined ? new Date() : new Date(timestamp));
    return date.getMonth().toString() + "_" + date.getYear().toString();
}

When I use it in JS to access an object propertiy, it works great :

myProperty = myObj[getTimeKey()]; // get the aray of activity for the current month

The problem is when I want to add an activity to my document / collection, getTimeKey() is interpreted as a string in the mongo query.

/*
** Add a new activity to a user activity feed
** Get the time key from the passed date
** Returns false if a required parameter is not defined
** If the user has already an activity feed started, then check if the time key exists
** If it exists, push it the new activity, else create it
** If the user do not already have an activity feed started, then create it
**
** PARAMETERS :
**      uid     -> user's activity feed to update
**      type    -> the type of activity, see below
**      data    -> some specific data, see below
**      date    -> (optionnal) the date of the event
**
** TYPES :
**      "ntt"   -> data: { tId: threadId }
**      "reply" -> data: { tId: threadId, pId: postId }
**      "mate"  -> data: { mId: mateId }
*/
addNewActivityTo = function (uid, type, data, date)
{
  if (uid && type && data && timeKey)
  {
    var feed = ActivityFeeds.findOne({_id: uid}, {fields: {getTimeKey(date): 1}});
    if (feed)
    {
      if (feed[getTimeKey(date)])
      {
        ActivityFeeds.update({_id: uid}, {
          $push: { getTimeKey(date): { type: type, data: data, date: date } }
        }, {multi: false});
      }
      else
      {
        ActivityFeeds.update({_id: uid}, {
          $set: { getTimeKey(date): [ { type: type, data: data, date: date } ] }
        }, {multi: false});
      }
    }
    else
    {
      ActivityFeeds.insert({
        _id: uid,
        getTimeKey(date): [ { type: type, data: data, date: date } ]
      });
      return { type: type, data: data, date: date };
    }
  }
  devError("Couldn't add new activity to user, parameters are missing.");
  return false;
}

What I want is to be able to create the wanted key in the query (for example, 7_2014 for september. of 2014) or to search for it. How can I make mongo understand that he must look for the return of getTimeKey() and not take it as a string ?

If I store getTimeKey() return like this : var timeKey = getTimeKey(date);, and replace every getTimeKey(date) by timeKey, it can insert it in the database, but the property key will be "timeKey". As it currently is, it throw me a Meteor build error because of the unexpected parenthesis.

Has anyone already faced that problem ?

Upvotes: 0

Views: 2080

Answers (2)

Thierry
Thierry

Reputation: 3155

Here's an example of how to build an activity feed with MongoDB: https://github.com/GetStream/mongodb-activity-feed

The Data Model The MongoDB activity feed project uses 5 different schemas:

  • Activity: The actual data of the activity Activity
  • Feed: An operation log. This stores that an activity should be added to a certain feed. (index on feed, time and operationTime)
  • Feed Group: A group of feeds, for example: user, notification, timeline etc. (unique on name)
  • Feed: A specific feed, ie user:scott, notification:josh, timeline:tom, etc. (unique on group and feedID)
  • Follow: A follow relationship between 2 feeds. (unique on source, target, index on target desc)

Upvotes: 0

Blakes Seven
Blakes Seven

Reputation: 50416

JavaSript "stringifies" all content on the "key" side when used in "Object Notation". Therefore use the "Array notation" to dynamically set keys from code:

var query = {_id: uid},
    projection = { "fields": {} };

projection["fields"][getTimeKey(date)] = 1;

var feed = ActivityFeeds.findOne(query, projection);

That makes the "projection" object in this case look like:

{ "fields": { "7_2014": 1 } }

Which is the sort of result you are after.

Upvotes: 1

Related Questions