{"id":22485797,"url":"https://github.com/GetStream/stream-node-orm","last_synced_at":"2025-08-02T18:33:41.597Z","repository":{"id":30898569,"uuid":"34456339","full_name":"GetStream/stream-node-orm","owner":"GetStream","description":"NodeJS Client - Build Activity Feeds \u0026 Streams with GetStream.io","archived":true,"fork":false,"pushed_at":"2023-01-11T11:19:00.000Z","size":619,"stargazers_count":131,"open_issues_count":23,"forks_count":21,"subscribers_count":42,"default_branch":"master","last_synced_at":"2024-04-15T00:17:53.200Z","etag":null,"topics":["activity-feed","feed","getstream-io","javascript","news-feed","nodejs","notification-feed","sailsjs","stream-node-orm","timeline","waterline"],"latest_commit_sha":null,"homepage":"https://getstream.io/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GetStream.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-23T12:59:01.000Z","updated_at":"2023-09-16T15:09:50.000Z","dependencies_parsed_at":"2023-01-14T17:54:48.402Z","dependency_job_id":null,"html_url":"https://github.com/GetStream/stream-node-orm","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-node-orm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-node-orm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-node-orm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-node-orm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GetStream","download_url":"https://codeload.github.com/GetStream/stream-node-orm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228499975,"owners_count":17929991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activity-feed","feed","getstream-io","javascript","news-feed","nodejs","notification-feed","sailsjs","stream-node-orm","timeline","waterline"],"created_at":"2024-12-06T17:13:15.550Z","updated_at":"2024-12-06T17:14:59.141Z","avatar_url":"https://github.com/GetStream.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"## Stream Node.js\n\n[![Build Status](https://travis-ci.org/tbarbugli/stream-node.svg)](https://travis-ci.org/tbarbugli/stream-node)\n[![npm version](https://badge.fury.io/js/getstream-node.svg)](http://badge.fury.io/js/getstream-node)\n[![Coverage Status](https://coveralls.io/repos/github/GetStream/stream-node-orm/badge.svg?branch=refactor-tests)](https://coveralls.io/github/GetStream/stream-node-orm?branch=refactor-tests)\n\n[![NPM](https://nodei.co/npm/getstream-node.png)](https://nodei.co/npm/getstream-node/)\n\n[stream-node-orm](https://github.com/GetStream/stream-node-orm) is a Node.js (Mongoose \u0026 Waterline) client for [Stream](https://getstream.io/).\n\nYou can sign up for a Stream account at https://getstream.io/get_started.\n\nNote there is also a lower level [Node.js - Stream integration](https://github.com/getstream/stream-js) library which is suitable for all JavaScript applications.\n\n### Build Activity Streams \u0026 News Feeds\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://dvqg2dogggmn6.cloudfront.net/images/mood-home.png\" alt=\"Examples of what you can build\" title=\"What you can build\"/\u003e\n\u003c/p\u003e\n\nYou can build:\n\n* Activity streams such as those seen on Github\n* A Twitter style newsfeed\n* A feed like Instagram or Pinterest\n* Facebook style newsfeeds\n* A notification system\n\n### Supported ORMs\n\nStream node currently supports:\n\n* Mongoose (full support, both serialization and enrichment)\n* Waterline (partial support, enrichment only)\n\n### Demo\n\nYou can check out our example app on Github [https://github.com/GetStream/Stream-Example-Nodejs](https://github.com/GetStream/Stream-Example-Nodejs)\n\n### Installation\n\n#### Step 1 - NPM\n\nInstall getstream_node package with npm:\n\n```npm install getstream-node --save```\n\n#### Step 2 - Config file\n\nCopy `getstream.js` config file from `node_modules/getstream-node` into the root directory of your application\nMake sure you require the getstream-node early on in your application (eg. in app.js)\n\n#### Step 3 - Get your API key\n\nLogin with Github on [getstream.io](https://getstream.io/) and edit the configuration values for\n```apiKey```, ```apiSecret``` and ```apiAppId``` in your `getstream.js` file (you can find them in the [dashboard](https://getstream.io/dashboard/)).\n\n### Model integration\n\nStream Node.js can automatically publish new activities to your feeds. To do that you only need to register the models you want to publish with this library.\n\n```js\nvar stream = require('getstream-node');\n\nvar tweetSchema = Schema({\n  text    : String,\n  user   : { type: Schema.Types.ObjectId, ref: 'User' }\n});\n\ntweetSchema.plugin(stream.mongoose.activity);\n\n// register your mongoose connection with the library\nstream.mongoose.setupMongoose(mongoose);\n```\n\nEvery time a Tweet is created it will be added to the user's feed. Users which follow the given user will also automatically get the new tweet in their feeds.\n\n#### Activity Fields\n\nModels are stored in feeds as activities. An activity is composed of at least the following fields: **actor**, **verb**, **object**, **time**. You can also add more custom data if needed.\nThe Activity mixin will try to set things up automatically:\n\n**object** is a reference to the model instance\n**actor** is a reference to the user attribute of the instance\n**verb** is a string representation of the class name\n\nBy default the actor field will look for an attribute called user or actor and a field called created_at to track creation time.\nIf your user field is called differently you'll need to tell us where to look for it.\nBelow shows an example how to set things up if your user field is called author.\n\n```js\nvar tweetSchema = Schema({\n  text    : String,\n  author   : { type: Schema.Types.ObjectId, ref: 'User' }\n});\n\ntweetSchema.plugin(stream.mongoose.activity);\n\ntweetSchema.methods.activityActorProp = function() {\n  return 'author';\n}\n```\n\n#### Customizing the Activity\n\nSometimes you'll want full control over the activity that's send to getstream.io.\nTo do that you can overwrite the default createActivity method on the model\n\n```js\ntweetSchema.methods.createActivity = function() {\n\t// this is the default createActivity code, customize as you see fit.\n      var activity = {};\n      var extra_data = this.activityExtraData();\n      for (var key in extra_data) {\n          activity[key] = extra_data[key];\n      }\n      activity.to = (this.activityNotify() || []).map(function(x){return x.id});\n      activity.actor = this.activityActor();\n      activity.verb = this.activityVerb();\n      activity.object = this.activityObject();\n      activity.foreign_id = this.activityForeignId();\n      if (this.activityTime()) {\n          activity.time = this.activityTime();\n      }\n      return activity;\n  }\n```\n\n### Feed Manager\n\nThis packages comes with a feed_manager class that helps with all common feed operations.\n\n#### Feeds Bundled with feed_manager\n\nTo get you started the manager has 4 feeds pre-configured. You can add more feeds if your application needs it.\nThe three feeds are divided in three categories.\n\n##### User Feed:\nThe user feed stores all activities for a user. Think of it as your personal Facebook page. You can easily get this feed from the manager.\n```js\nFeedManager.getUserFeed(req.user.id);\n```\n\n##### News Feeds:\nThe news feeds store the activities from the people you follow.\nThere is both a flat newsfeed (similar to twitter) and an aggregated newsfeed (like facebook).\n\n```js\nvar flatFeed = FeedManager.getNewsFeeds(foundUser._id)['timeline_flat'];\nvar aggregatedFeed = FeedManager.getNewsFeeds(req.user.id)['timeline_aggregated'];\n```\n\n##### Notification Feed:\nThe notification feed can be used to build notification functionality.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://feedly.readthedocs.org/en/latest/_images/fb_notification_system.png\" alt=\"Notification feed\" title=\"Notification feed\"/\u003e\n\nBelow we show an example of how you can read the notification feed.\n```js\nvar notificationFeed = FeedManager.getNotificationFeed(req.user.id);\n```\n\nBy default the notification feed will be empty. You can specify which users to notify when your model gets created. In the case of a retweet you probably want to notify the user of the parent tweet.\n\n```js\ntweetSchema.methods.activityNotify = function() {\n  if (this.isRetweet) {\n\t  target_feed = FeedManager.getNotificationFeed(this.parent.author.id);\n\t  return [target_feed];\n  }\n};\n```\n\nAnother example would be following a user. You would commonly want to notify the user which is being followed.\n\n```js\nfollowSchema.methods.activityNotify = function() {\n  target_feed = FeedManager.getNotificationFeed(this.target._id);\n  return [target_feed];\n};\n```\n\n#### Follow a Feed\nTo follow the created newsfeeds you need to notify the system about follow relationships. The manager comes with APIs to let a user's news feeds follow another user's feed. This code lets the current user's flat and aggregated feeds follow the target_user's personal feed.\n\n```\nFeedManager.followUser(userId, targetId);\n```\n\n### Showing the Newsfeed\n\n#### Activity Enrichment\n\nWhen you read data from feeds, a like activity will look like this:\n\n```js\n{'actor': 'User:1', 'verb': 'like', 'object': 'Like:42'}\n```\n\nThis is far from ready for usage in your template. We call the process of loading the references from the database enrichment. An example is shown below:\n\n```js\nrouter.get('/flat', ensureAuthenticated, function(req, res, next){\n    var flatFeed = FeedManager.getNewsFeeds(req.user.id)['timeline_flat'];\n\n    flatFeed.get({})\n    \t.then(function (body) {\n        \tvar activities = body.results;\n        \treturn StreamBackend.enrichActivities(activities);\n        })\n        .then(function (enrichedActivities) {\n            return res.render('feed', {location: 'feed', user: req.user, activities: enrichedActivities, path: req.url});\n        })\n        .catch(next)\n    });\n});\n```\n\nPromises are used to pipe the asynchronous result of `flatFeed.get` and `StreamBackend.enrichActivities` through our code.\n\n### Temporarily Disabling the Model Sync\n\nModel synchronization can be disabled manually via environment variable.\n\n```js\nNODE_ENV=test npm test\n```\n\n#### Automatically Populate Paths:\n\nYou can automatically populate paths during enrichment via the pathsToPopulate static.\n\n```js\ntweetSchema.statics.pathsToPopulate = function() {\n  return ['link'];\n};\n```\n\n### Full Documentation and Low Level APIs Access\n\nWhen needed you can also use the [low level JavaScript API](https://github.com/getstream/stream-js) directly. Documentation is available at the [Stream website](https://getstream.io/docs/?language=js).\n\n```js\nvar streamNode = require('getstream-node');\nvar client = streamNode.FeedManager.client\n// client.addActivity, client.removeActivity etc are all available\n```\n\n### Enrichment\n\nYou can use the enrichment capabilities of this library directly.\n\n```js\nvar streamNode = require('getstream-node');\nvar streamMongoose = new streamNode.MongooseBackend()\n// or\nvar streamWaterline = new streamNode.WaterlineBackend()\n// now enrich the activities\nstreamWaterline.enrichActivities(activities).then(function(enrichedActivities) {\n\tres.json({'results': enrichedActivities})\n}).catch(function(err) {\n\tsails.log.error('enrichment failed', err)\n\treturn res.serverError('failed to load articles in the feed')\n})\n```\n\n### Customizing Enrichment (since 1.4.0)\n\nBy default the enrichment system assumes that you're referencing items by their id. Sometimes you'll want to customize this behavior. You might for instance use a username instead of an id. Alternatively you might mant to use a caching layer instead of the ORM for loading the data. The example below shows how to customize the lookup for all User entries.\n\n```js\n// subclass streamMongoose\nfunction streamCustomEnrichment() {};\nstreamCustomEnrichment.prototype = {\n    loadUserFromStorage: function(modelClass, objectsIds, callback) {\n        var found = {};\n        var paths = [];\n        if (typeof(modelClass.pathsToPopulate) === 'function') {\n            var paths = modelClass.pathsToPopulate();\n        }\n\t// Here's the magic, use a username instead of id\n        modelClass.find({\n            username: {\n                $in: objectsIds\n            }\n        }).populate(paths).exec(function(err, docs) {\n            for (var i in docs) {\n                found[docs[i]._id] = docs[i];\n            }\n            callback(err, found);\n        });\n    }\n}\nutil.inherits(streamCustomEnrichment, streamNode.mongoose.Backend);\n```\n\n### Contributing\n\nRunning tests:\n\n```\nnpm test\n```\n\n### Releasing\n\nMake sure your working directory is clean and run:\n\n```\nnpm install\nnpm version [ major | minor | patch ]\nnpm publish\n```\n\n### Supported Node.js Versions\n```\nv10.x\nv12.x\nv14.x\n```\n\n### Copyright and License Information\n\nCopyright (c) 2015-2017 Stream.io Inc, and individual contributors. All rights reserved.\n\nSee the file \"LICENSE\" for information on the history of this software, terms \u0026 conditions for usage, and a DISCLAIMER OF ALL WARRANTIES.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGetStream%2Fstream-node-orm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGetStream%2Fstream-node-orm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGetStream%2Fstream-node-orm/lists"}