Enrichment

One essential best-practice when integrating with Stream is to keep your data normalized and use references to objects instead of full objects inside activities. The What To Store section covers this topic.

In most cases, it is better to store a reference inside your activities instead of an entire object. Doing so will make it easier to update data, and it will avoid complex sync problems. Because of this, a correct integration with Stream stores references to objects when adding activities and replaces them with full objects when reading the feeds. For example: if your activities have users as actors, your application will store the user ID in the actor field and replace the ID value with the user object before rendering the feed.

The process of replacing objects to refs and refs to objects is called “Enrichment” and can be done in two different ways.

Enrichment Using Stream Collection and User Endpoints

The simplest way to organize your data is to store objects and users within Stream using collections and the user’s API endpoints. You can then embed them inside your activities. With this method, you don’t have to implement any server-side logic to convert objects into references and references back into objects. Activities read from the APIs will be fully enriched with your data.

Another advantage is that you can now read feeds and add activities directly from your frontend or mobile app.

Enrichment Using Your Own Database (Backend)

If you only talk to Stream from the backend and you must keep data on your servers, the best approach is to use your own database for the enrichment process. Both the APIs and the API clients will make this very easy.

To clarify, we want to translate this:

{
  actor: 'User:1',
  verb: 'pin', 
  object: 'Place:42'
};

Into this (UserObject, PlaceObject and BoardObject are the objects stored in your database) :

{
  actor: UserObject,
  verb: 'pin', 
  object: PlaceObject
};

Stream provides enrichment out-of-the-box for some of the most popular ORMs. Please find below the examples for how to enrich activities using different combinations of frameworks/ORMs

// Using Waterline
// https://github.com/GetStream/stream-node-orm
const streamNode = require('getstream-node');
const streamWaterline = new streamNode.WaterlineBackend();

streamWaterline.enrichActivities(activities).then(function(enrichedActivities) {
  res.json({'results': enrichedActivities})
}).catch(function(err) {
  sails.log.error('enrichment failed', err)
  return res.serverError('failed to load articles in the feed')
});

// Using Mongoose
// https://github.com/GetStream/stream-node-orm
const streamNode = require('getstream-node');
const streamMongoose = new streamNode.MongooseBackend();

streamMongoose.enrichActivities(activities).then(function(enrichedActivities) {
  console.log(enrichedActivities)
}).catch(function(err) {
  console.log('error', err)
});

Feel free to reach out if your favorite ORM or Framework is missing.

Collections & Users

Stream allows you to store arbitrary data with the collections and users API endpoints. Data stored this way can also be embedded inside activities so that enrichment is done automatically on Stream’s side.

Here are a few examples of how you can embed a user and an object inside an activity:

const feed = client.Feed("user", "jack");

// make sure we have the user data on Stream
const userData = new Dictionary<string, object>
{
    { "name", "Jack"},
    {"profile_picture", "https://goo.gl/XSLLTA"}
};
const user = await client.Users.AddAsync("jack", userData, true);

// then create a post inside a collection
const collectionData = new Dictionary<string, object>();
collectionData.Add("text", "...");
const item = await client.Collections.AddAsync("post", collectionData, "42-ways-to-improve-your-feed");

// add the activity with user and post objects references
const activity = new Activity(user.Ref(), "post", item.Ref("post"));
await feed.AddActivityAsync(activity);

// if we now read Jack's feed we will get automatically the enriched data
await feed.GetEnrichedFlatActivitiesAsync();

// we can also update Jack's post and get the new version automatically propagated to his feed and its followers client.collections.update("items", item["id"], data={text:"new version of the post"})

More on how to work with references to collections and users can be found here.

© Getstream.io, Inc. All Rights Reserved.