And they work the same as you expect, from the inversed side as well.
I know what question comes to your mind right now, what if I want to put a field inside the metadata,
I want to store who added that user (`addedBy`) to that link and fetch it, how do we do ?
Currently, this is not possible, because it has deep implications with how the Hypernova Module works,
but you can achieve this in a very performant way, by abstracting it into a separate collection:
```js
// file: /imports/db/groupUserLinks/links.js
import Groups from '...';
import GroupUserLinks from '...';
GroupUserLinks.addLinks({
user: {
type: 'one',
collection: Meteor.users,
field: 'userId'
},
adder: {
type: 'one',
collection: Meteor.users,
field: 'addedBy'
},
group: {
type: 'one',
collection: Meteor.users,
field: 'groupId'
}
})
// file: /imports/db/users/links.js
Meteor.users.addLinks({
groupLink: {
collection: GroupUserLinks,
type: 'one',
field: 'groupLinkId',
}
})
```
And the query will look like this:
```js
Meteor.users.createQuery({
groupLink: {
group: {
name: 1,
},
adder: {
firstName: 1
},
roles: 1,
createdAt: 1,
}
})
```
## Link Loopback
No one stops you from linking a collection to itself, say you have a list of friends which are also users:
```js
Meteor.users.addLinks({
friends: {
collection: Meteor.users,
type: 'many',
field: 'friendIds',
}
});
```
Say you want to get your friends, and friends of friends, and friends of friends of friends!
```js
Meteor.users.createQuery({
$filters: {_id: userId},
friends: {
nickname: 1,
friends: {
nickname: 1,
friends: {
nickname: 1,
}
}
}
});
```
## Uniqueness
The `type: 'one'` doesn't necessarily guarantee uniqueness from the inversed side.
For example, if we have inside `Comments` a link with `Posts` with `type: 'one'` inside postId,
it does not mean that when I fetch the posts with comments, comments will be an array.
But if you want to have a one to one relationship, and you want grapher to give you an object,
instead of an array you can do so:
```js
Meteor.users.addLinks({
paymentProfile: {
collection: PaymentProfiles,
inversedBy: 'user'
}
});
PaymentProfiles.addLinks({
user: {
field: 'userId',
collection: Meteor.users,
type: 'one',
unique: true
}
})
```
Now fetching:
```js
Meteor.users.createQuery({
paymentProfile: {
type: 1,
last4digits: 1,
}
});
```
`paymentProfile` inside `user` will be an object because it knows it should be unique.
## Data Consistency
This is referring to having consistency amongst links.
Let's say I have a `thread` with multiple `members` from `Meteor.users`. If a `user` is deleted from the database, we don't want to keep unexisting references.
So after we delete a user, all threads containing that users should be cleaned.
This is done automatically by Grapher so you don't have to deal with it.
The only rule is that `Meteor.users` collection needs to have an inversed link to `Threads`.
In conclusion, if you want to benefit of this, you have to define inversed links for every direct links.
## Autoremoval
```js
Meteor.users.addLinks({
'posts': {
collection: Posts,
inversedBy: 'author',
autoremove: true
}
});
```
After you deleted a user, all the links that have `autoremove: true` will be deleted.
This works from the `direct` side as well, not only from `inversed` side.
## Indexing
As a rule of thumb, you must index all of your links. Because that's how you achieve absolute performance.
This is not done by default, to allow the developer flexibility, but you can do it simply enough from the direct side definition of the link:
```js
PaymentProfiles.addLinks({
user: {
field: 'userId',
collection: Meteor.users,
type: 'one',
unique: true,
index: true,
}
})
```
The index is applied only on the `_id`, meaning that if you have `meta` links, other fields present in that object will not be indexed.
If you have `unique: true` set, the index will also apply a unique constraint to it.
## Top Level Fields
Grapher currently supports only top level fields for storing data. One of the reasons it doesn't allow nested fields
is to enforce the developer to think relational and eliminate large and complex documents by abstracting them into collections.
In the future, this limitation may change, but for now you can work around this and keep your code elegant.