When storing all the users in a group (to avoid full collection search), is it better to use object keys or Array?

#1

Say I wan’t to check if a user belongs to a group, to check if it has permission to access content.

I can either do:

GroupUsersCollection example documents:

A) {_id, userIds:['eu4jg94jbmt84', '493jgnrkejs']}

B) {_id, _eu4jg94jbmt84:1, _493jgnrkejs:1}

In the second example, the users are fields in the object (prefixing with underscore as user ids can start with a number).

The second example is also good for subscriptions, I believe, as any change in the “userIds” array of example ‘A’ would send to the client the entire modified array.

Also, I’ve read that object key lookup is faster than indexOf/includes.

So, what do you think?
Is there a better way?

#2

This question is a bit too lose to be answered cleanly. So, some things to consider:

  1. Mongo max document size is 16MB - so if you have a few groups, with lots of users - you’ll need to consider this. Consider storing groupIds on a user instead, it will depend on how frequenlty a user’s groups change (vs how frequently you add a new user to a group) and how many users exist per group (or vice versa)
  2. If you are separating out a GroupUsersCollection anyway - why not just store pairs { userId: "", groupId: "" }. This solves the max document size problem, the indexing problem, and the efficiency of publications problem. The drawback of course is that you now have a “relational” table.
  3. Arrays can be indexed - so if you had a Groups collection with documents: { _id: "", userIds: ["id1", "id2"]} - you can add an index on the userIds field to enable faster lookups
  4. the _ prefix isn’t necessary, you can use pure numbers as keys of an object if you wish. It is extremely difficult (impossible?) to add indexes to dynamic keys within a document.
1 Like
#3

Thanks for your reply!
The amount of users per group will be limited to 100-1000 (it’s a chat app), so the 16mb woudln’t be a concern unless the app grows and attempts to be a social network.

Consider storing groupIds on a user instead

I believe it would be the same, as a user might belong to 50 groups and groups might have 50 users.

why not just store pairs

What I’m trying to avoid is full collection search. As the server will constantly be checking for users’ permissions.
So checking in an object with say, 100 user ids would be faster than scanning the entire collection for a match.

#4

This is not the case if you add proper indexes. With a compound index on groupId/userId field set the query could return after scanning a single document. With Meteor’s architecture, I definitely recommend using a relational table approach here. If you need some good examples of this architecture, check out the code in any of the Socialize packages. Particularly the socialize:messaging.

1 Like