On this page

Users, channels, and memberships in DataSync

Users, channels, and memberships are DataSync's built-in classes: a user and a channel are entities, and a membership is a relationship linking a channel to a user. Everything on the Data model page applies to them too, including payloads, ETags, TTL, events, and access control.

Users

A user is an entity of the built-in Global User entity class, which PubNub seeds at version 1. DataSync picks the class for you when you don't name one. Creating a user requires only entityClassVersion. The id is optional, and DataSync generates one if you omit it, as are status and payload.

The user endpoints are Get users, Get user, Create user, Update user, Patch user, and Delete user.

A user's fields:

FieldPurpose
id
The user ID
createdAt
Creation timestamp
updatedAt
Last modification timestamp
eTag
Optimistic concurrency marker
status
A free-form application lifecycle string, 1 to 100 characters
expiresAt
Expiry timestamp. An instance of the Global class inherits its 30-day TTL
entityClass
The name of the entity class, User unless you've extended it
entityClassVersion
The version of the User class this instance pins to
entityClassLevel
Whether that class is Global or SubKey (keyset-level)
payload
Your application data
icon

How this differs from App Context user metadata

The Global User class itself can't be changed. To add your own fields, use Create a new entity class to define a class on your keyset that extends the Global User class as its parent, through an extends reference (see Class inheritance).

The subclass name is up to you, it does not need to match the parent's. You create, read, and list instances of your extended class, the same as any other Global User, and they validate and project against your extended definition while still being users in every other sense (the same users resource type for Access Manager grants, the same fields table above).

Your subclass can't itself be extended. A class can only extend a class defined at a higher level, so a keyset-level class extends a Global class and the hierarchy stops there.

In Bob's marketplace, Bob defines a keyset-level MarketplaceUser class at version 1, extending the Global User class, adding display_name, avatar_url, email, and phone. user-alice is a user entity created against that version, with a payload of

{ "name": "Alice", "type": "shopper", "display_name": "Alice", "avatar_url": "https://.../alice.png", "email": "alice@example.com", "phone": "+1-555-0100" }

You can't modify the Global class, so you extend it. A subclass inherits its parent's properties automatically: MarketplaceUser declares only Bob's four fields, and inherits name (/payload/name, string, nullable) and type (/payload/type, string, nullable) from the parent, for six effective properties in all. If you do redeclare an inherited property yourself, its path, value kind, and nullability must match the parent exactly, or the class is rejected, but you're free to pick a different filtering mode or a different set of projections for an inherited property.

Channels

A channel is an entity of the built-in Global Channel entity class, with the same shape as a user. Refer to the fields table above for the channel's fields, they are the same as a user's.

A channel entity stores data about a channel your app uses for messaging, for example a display name or a category.

The channel endpoints are Get channels, Get channel, Create channel, Update channel, Patch channel, and Delete channel.

A channel entity in DataSync isn't a pub/sub channel

Creating a channel entity doesn't create or configure the underlying Pub/Sub channel, and a channel does not need an entity for messaging to work.

The entity is where the channel's metadata lives.

The channel entity holds metadata, while the Pub/Sub and Presence channel carries messages and subscribers. They share an ID but have separate lifecycles, and messaging works whether or not the entity exists.

In Bob's marketplace, channel-summer-sale is a channel entity with a payload of

{ "name": "Summer Sale Live", "type": "live-stream" }

Memberships

A membership is a relationship of the built-in Global Membership relationship class, linking a channel and a user. The Membership class is many-to-many, so a user can belong to many channels and a channel can have many members. Its two sides are pinned to the Global classes: entity A must be a Channel and entity B must be a User, or a subclass of either.

The membership endpoints are Get memberships, Get membership, Create membership, Update membership, Patch membership, and Delete membership.

A membership's fields, in addition to the system fields shared with entities:

FieldPurpose
id
The membership's own identifier, and the only handle for get, replace, partial update, and delete. There's no addressing a membership by its channel and user pair
channelId
The linked channel's ID, the relationship's entity A
userId
The linked user's ID, the relationship's entity B
relationshipClass
Always Membership, set by DataSync. Relationship classes can't be extended
relationshipClassVersion
The version of the Membership class this instance pins to
payload
Association data, for example a role

A membership is a relationship, so it follows every relationship rule on the Data model page, with a few specializations:

  • The sides are renamed. Where a generic relationship exposes entityAId and entityBId, a membership exposes them as channelId and userId.
  • relationshipClass is fixed to Membership and can't be supplied.
  • The channel must be a Channel, or a subclass of it, and the user must be a User, or a subclass of it, or the request is rejected with a 400.
  • expiresAt is derived as the earlier of the channel's and the user's expiry, and can't be set.
  • DataSync events keep the generic entityAId and entityBId names.

Creating a membership requires channelId, userId, and relationshipClassVersion. The id is optional, as are status and payload. Both the channel and the user must already exist, or the request returns a 404. Only one membership can exist for a given channel and user, so a duplicate returns a 409.

Memberships support both replace (PUT) and partial update (PATCH), the same as any other relationship. Refer to Data operations for more information.

In Bob's marketplace, Alice's membership in channel-summer-sale carries a payload of

{ "role": "viewer" }

Because the Membership class declares no properties and can't be extended, membership payload fields are never indexed. You can't filter or sort memberships by role. The built-in fields id, createdAt, updatedAt, and status still work, so you can order memberships by when they were created even though the payload isn't searchable.

Membership lists can be narrowed by user_id, by channel_id, or by both together, which covers the two common questions: which channels a user belongs to, and who is a member of a channel. Both parameters are optional, so omit them to list every membership. Refer to Get memberships.

Real-time updates

Creating, updating, or deleting a user, channel, or membership can publish a DataSync event, the same way any other entity or relationship can. Events are off by default and are enabled per class version, per keyset, in the Admin Portal. A create event for user-alice is published on the user-alice channel. Update and delete events are also published on the channels of every entity user-alice is linked to. A membership event is published on both the linked channel's and the linked user's channels, never on the membership's own ID. Refer to Events for more information.

Because a membership event lands on the linked user's and channel's ID channels, the way to watch Alice's memberships appear and disappear is to subscribe to user-alice, not to any membership id. SDKs that ship DataSync SDK entities expose that as a user handle and a channel handle. A membership handle exists for symmetry, but it receives nothing for the link itself.

icon

Comparison with App Context

Creating user-alice against Bob's MarketplaceUser class, then reading her back by id:

1const created = await pubnub.dataSync.createUser({
2 id: 'user-alice',
3 class: 'MarketplaceUser',
4 data: {
5 classVersion: 1,
6 payload: {
7 name: 'Alice',
8 type: 'shopper',
9 display_name: 'Alice',
10 avatar_url: 'https://.../alice.png',
11 email: 'alice@example.com',
12 phone: '+1-555-0100',
13 },
14 },
15})
show all 17 lines

Refer to Create user (JavaScript), Create user (C#), and Create user (REST) for the full parameter reference, including the equivalent methods for channels and memberships.