Schemas & Collections

The role of the schema is to serve as a central source of truth that will be used to generate or populate many of Vulcan’s other components.

/images/vulcan-schemas.svg

Based on your schema, Vulcan can:

Example

Here is a schema example, taken from the Movies tutorial:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
const schema = {
// default properties

_id: {
type: String,
optional: true,
canRead: ["guests"]
},
createdAt: {
type: Date,
optional: true,
canRead: ["guests"],
onCreate: ({ newDocument, currentUser }) => {
return new Date();
}
},
userId: {
type: String,
optional: true,
canRead: ["guests"],
resolveAs: {
fieldName: "user",
type: "User",
resolver: (movie, args, context) => {
return context.Users.findOne(
{ _id: movie.userId },
{
fields: context.Users.getViewableFields(
context.currentUser,
context.Users
)
}
);
},
addOriginalField: true
}
},

// custom properties

name: {
label: "Name",
type: String,
optional: true,
canRead: ["guests"],
canCreate: ["members"],
canUpdate: ["members"]
},
year: {
label: "Year",
type: String,
optional: true,
canRead: ["guests"],
canCreate: ["members"],
canUpdate: ["members"]
},
review: {
label: "Review",
type: String,
optional: true,
control: "textarea",
canRead: ["guests"],
canCreate: ["members"],
canUpdate: ["members"]
}
};

As you can see, a schema is a JavaScript object containing a list of fields, each of which is defined using a range of special properties.

Creating Collections

Vulcan features a number of helpers to make setting up your layer faster, most of which are initialized through the createCollection function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const Movies = createCollection({
typeName: 'Movie',

collectionName: 'Movies',

schema,

resolvers,

mutations,

permissions,

filters,

defaultInput,

components,

generateGraphQLSchema,
});

The function takes the following arguments:

  • typeName: the name of the GraphQL type that will be generated for the collection.
  • collectionName: optionally, the name of the collection throughout your app (will be lowercased in your MongoDB database). If not provided it will be the plural of your type name.
  • dbCollectionName: if you want to use a different name in your database you can specify it here.
  • schema, resolvers, mutations: see below.
  • permissions: an object defining the collection’s document-level permissions
  • filters: an object defining filters to enhance collection queries.
  • defaultInput: an object defining the collection’s default query input.
  • components: an object containing helper components.
  • resolvers (optional): an object containing single and multi query resolvers.
  • mutations (optional): an object containing create, update, upsert, and delete mutation resolvers.
  • generateGraphQLSchema: whether to use the objects passed above to automatically generate the GraphQL schema or not (defaults to true).

Note that if you do not specify resolvers or mutations, default query resolvers and mutation resolvers will be generated for you.

Alternative Approach

Passing a schema, a resolver, and a mutation to createCollection enables a lot of Vulcan’s internal synergy. That being said, you can also set generateGraphQLSchema to false and use the custom schemas, custom resolvers, and custom mutations utilities documented below to bypass this if you prefer.

Extending Collections

You can extend a collection’s options with extendCollection(collection, options). For example:

1
2
3
4
5
6
7
extendCollection(Posts, { 
callbacks: {
create: {
after: [ notifyAdmins ]
}
}
});

This can be useful when you want to declare a collection in a file shared by both client and server, but want to add some options (such as callbacks) only on the server.

Note that this works for all options except the schema, which is initialized with the initial createCollection. To extend the schema, see addField below.

Extending Schemas

Sometimes, you’ll want to extend an existing schema. For example Vulcan’s Forum example has three main collections: Posts, Users, and Comments. Each of them has a pre-set schema, but that schema can also be extended with custom fields.

This is how the vulcan:newsletter package extends the Posts schema with a scheduledAt property that keeps track of when a post was sent out as part of an email newsletter:

1
2
3
4
5
6
7
Posts.addField({
fieldName: "scheduledAt",
fieldSchema: {
type: Date,
optional: true
}
});

The collection.addField() function takes either a field object, or an array of fields. Each field has a fieldName property, and a fieldSchema property.

Each field schema supports all of the SimpleSchema properties, such as type, optional, etc.

A few special properties (canRead, canCreate, canUpdate, input, and order) are also supported by the Forms package.

You can also remove a field by calling collection.removeField(fieldName). For example:

1
Posts.removeField("scheduledAt");
Edit on GitHub