How is mongo supposed to be structured?

Say I have a user. A user has groups and roles (using alanning:roles). For each group, a user has a profile for each role he is in in that group. Here is a more practical example:

{
  _id: "1234",
  profile: {
    name: 'Corvid',
    repositories: [{
      _id: "1",
      reviewer: {
        'pull-requests': {
          approved: [
            { _id: "1", lastAction: Date },
            {_id: "2", lastAction: Date }
          ],
          denied: [
            { _id: "3", lastAction: Date },
            { _id: "4", lastAction: Date }
          ]
        }
      }
    }, {
      _id: "2",
      editor: {
        'pull-requests': {
          submitted: [
            { _id: "7", lastAction: Date },
            { _id: "8", lastAction: Date }
          ]
        }
      }
    }, {
      _id: "3",
      owner: {}
    }]
  },
  roles: {
    1: ['reviewer'],
    2: ['contributor'],
    3: ['owner']
  }
}

Now here’s a few things I really don’t understand… let’s say the user above is called user A.

Filtering to only shared groups

user B visits user A’s profile. User B belongs to groups 1, 2, and 4. I want to filter the fields of repositories to only those documents shared by both user A and user B, which is to say, repositories 1 and 2. I simply cannot find any way for this to be managed in a publication. The only solution seems to limit it to only ONE result.

Meteor.users.find({
  _id: userId,
  'profile.repositories._id': {
    $in: Meteor.users.findOne(this.userId).profile.repositories.map(repo => repo._id)
  }
}, {
  fields: { 'profile.repositories.$': 1 }
})

The only way I know of is through an overly complex series of observers that explicitly exclude these repositories

Updating a many-to-many relationship within a many-to-many relationship

So now say I want to update the lastAction within repository 1 and pull-request with the id of 1. This will not work

Meteor.users.update({
  _id: userId,
  'profile.repositories._id': '1',
  'profile.repositories.pull-requests.submitted._id': '5'
}, {
  $set: { 'profile.repositories.$.pull-requests.submitted.$.lastAction': new Date }
});

Really, I just don’t get how mongo wants to be used. It seems like it’s just completely worthless for any actual relational data, and only serves for shiny reactivity purposes

1 Like

Mongo is a document store, not a relational database. You will run into this limitation of Mongo, but you can do reactive joins. It’s just a little bit hacky :wink: .

eh, I don’t really get why meteor chose to use mongo then. I mean, maybe for user configuration or schema-less data… why not use something like postgres?

Mongo allows you to prototype quickly since you don’t have to worry about Schemas. Especially when introducing someone to a framework, it’s good to be able to quickly insert data without having to worry about making a schema, setting up relations, and making sure your data conforms to that schema.

But, I agree, I wish MDG had a SQL solution backed in that you could swap with Mongo.

1 Like