How can I populate properties of array item in mongoDB? - mongodb

I have 3 collections scopes, groups and users
const ScopesSchema = new mongoose.Schema(
{
name: String,
privilege: String,
}
);
const GroupsSchema = new mongoose.Schema(
{
name: String,
status: String,
}
);
const UserSchema = new mongoose.Schema(
{
security:[{
_id:false,
group: { type: mongoose.Schema.Types.ObjectId, ref: "groups" },
scopes: [{ type: mongoose.Schema.Types.ObjectId, ref: "scopes" }],
}],
},
);
Is possible to populate data from properties group and scopes in a document like this?
{
_id: 44ffbvb...,
security: [{
"group": "44ffbvb...", // ID of document in groups collection
"scopes": ["44ffbvb...","44ffbvb..."] // IDs of documents in scopes collection
}]
}
I'd like to get the information related to group and scopes in order to get a document like this:
{
_id: 44ffbvb...,
security: [{
"group": {
"id" : "44ffbvb...",
"name" : "Name of the group",
"status": "ACTIVE"
},
"scopes": [{name: "ADMINISTRATOR", privilege: "write-only" },{name: "ROOT", privilege: "read-only" }]
}]
}

you can use the npm package
mongoose-autopopulate
The fields you need to be populated, add : autopopulate: true,
and add this line to the schema-
schema.plugin(require('mongoose-autopopulate'));

Related

How to return the object in an array object in mongoose

I currently have a UserModel and a House model where the house model contains an array of user objects. However, when I return I want to return an array of user objects instead of just users objectId. How do I accomplish this?
For example, if I run
HouseModel.findbyId("asdf")
it returns:
_id: "asdf"
"name": "name",
"users": [
"620044aa7811fb4ab4619e44",
"620044aa7811fb4ab4619e45"
],
Any help would be appreciated
but I want to return:
``
_id: "asdf"
"name": "name",
"users": [
{_id: "620044aa7811fb4ab4619e44", name: "bob" age: 7,},
{_id: "620044aa7811fb4ab4619e45", name: "bob" age: 7,}
],
``
HouseSchema
const houseSchema = new mongoose.Schema({
name: {
type: String,
required: false
},
users: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
default: [],
required: true,
}
],
UserSchema
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
},
age: {
type: Number,
required: false,
unique: true,
},
use populate
HouseModel.findbyId("asdf").populate('users')

MongoDB - remove many from arrays of all existing elements

I have some simple user data. Here is example for one user:
const userSchema = new Schema({
userName: {
type: String,
},
projectsInput: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
projectsHold: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
});
I want by having ProjectId to be able to remove all records from all users that contains it.
if I get the first one
60f02d21159c4b4110f21a32
how I can perform updateMany function for my UserModel?
return UserModel.updateMany(
{
projectsInput: {
$elemMatch: args.projectId,
},
},
{
projectsInput: {
$slice: [projectsInput.$, 1],
},
}
);
})
Here is my code that is not working.
args.projectId = 60f02d21159c4b4110f21a32 (my id for the project I want to delete)
and UserModel is my mongodb Schema for user.
you can use $pull
{
$pull: {
projectsInputs: "123"
}
}

GraphQL Mutation Updating Users Followers with Mongoose/MongodDB - $set is empty error

I have this mutation set up:
followUser: {
type: UserType,
args: {
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString)},
},
resolve(parentValue, { firebaseUid, _id, following}) {
const update = {
$set: { "following": [firebaseUid] },
$push: { "following": { firebaseUid } }
}
return UserSchema.findOneAndUpdate(
{ _id },
update,
{new: true, upsert: true}
)
}
},
I'm trying to add new followers into my graphql user's collection. My user model:
const UserSchema = new Schema(
{
firebaseUid: String,
following: [{ type: Schema.Types.ObjectId, ref: 'User' }],
followers: [{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
So at first, the user doesn't have any followers, so it won't have that field yet. When user adds someone to their friends list, thats when the field will appear in mongodb. Right now I'm getting this error:
"message": "'$set' is empty. You must specify a field like so: {$set: {<field>: ...}}",
I'm not sure if I'm doing the $set correctly.
The UserType
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString) },
followers: { type: new GraphQLList(GraphQLString) },
...
})
});
edit:
current mongodb data collection:
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
after running the update
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
following: ["fdsaduybfeaf323dfa"] // <-- this gets added
Currently mongooses validator is rejecting the update. To fix this you need the following:
You only need to $push since it will automatically create an array if the property does not exist
You should remove the extra { } around the firebaseUid in the $push because otherwise the following array will contain objects with a firebaseUid property instead of directly containing the Uid (or would if the schema validator allowed it)
Mongo ObjectIds can only be converted from strings when they are 12-byte hexadecimal, and firebaseUid is not, so the schema should be typed to String instead of ObjectId as the validator will reject the field for update otherwise.

MongoDB / Mongoose one-to-many relationship

Working on a database structure for a new project, and trying to figure out how exactly one-to-many relationships in MongoDB / mongoose work.
So considering a following simple structure :
I have a project table/schema with multiple images linked to it:
const ProjectSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId, // Just the id,
name: { type: String, required: true, trim: true, maxLength: 60 },
description: { type: String, required: false },
images: [{
type: Schema.Types.ObjectId, ref: 'Image'
}]
});
And then an image table/schema:
const ImageSchema = new Schema({
_id: mongoose.Types.ObjectId, // Just the id,
url: { type: String, unique: true, required: true }
project: {
type: Schema.Types.ObjectId, ref: 'Project'
}
});
I want one-to-many between images and projects, so I save an image with a project id:
const image = new Image(
{
project: project._id,
_id: new mongoose.Types.ObjectId(),
url: 'https://someurl',
});
await image.save();
If I then find this image, and populate the project field - it contains all the project's info nicely, BUT if I find this project, it doesn't have anything in the images array (referencing Image):
images: [{
type: Schema.Types.ObjectId, ref: 'Image'
}]
I thought that with ref you're creating the foreign key reference between Project and Image and then both Image should have the linked Project and Project should see the linked image in the array.
Is that not the case or am I missing something here ?
You should be able to populate images from project with no problem.
Let's say you have this project document:
{
"_id" : ObjectId("5e592a438b93764a40a81a96"),
"images" : [
ObjectId("5e592aba8b93764a40a81a98"),
ObjectId("5e592ac78b93764a40a81a99")
],
"name" : "Project 1",
"__v" : 0
}
And these image documents:
{
"_id" : ObjectId("5e592ac78b93764a40a81a99"),
"url" : "Url 2",
"project" : ObjectId("5e592a438b93764a40a81a96"),
"__v" : 0
},
{
"_id" : ObjectId("5e592aba8b93764a40a81a98"),
"url" : "Url 1",
"project" : ObjectId("5e592a438b93764a40a81a96"),
"__v" : 0
}
We can use the following code to populate images:
router.get("/projects/:id", async (req, res) => {
const result = await Project.findById(req.params.id).populate("images");
res.send(result);
});
This will give a result like this:
{
"images": [
{
"_id": "5e592aba8b93764a40a81a98",
"url": "Url 1",
"project": "5e592a438b93764a40a81a96",
"__v": 0
},
{
"_id": "5e592ac78b93764a40a81a99",
"url": "Url 2",
"project": "5e592a438b93764a40a81a96",
"__v": 0
}
],
"_id": "5e592a438b93764a40a81a96",
"name": "Project 1",
"__v": 0
}
So for your case, check if your project document really contains images array with the Object ids for image documents, and you populate correctly.
Also you don't need to add _id fields to the schema, mongodb will itself generate _id automatically.
project
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ProjectSchema = Schema({
name: { type: String, required: true, trim: true, maxLength: 60 },
description: { type: String, required: false },
images: [
{
type: Schema.Types.ObjectId,
ref: "Image"
}
]
});
module.exports = mongoose.model("Project", ProjectSchema);
image
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ImageSchema = new Schema({
url: { type: String, unique: true, required: true },
project: {
type: Schema.Types.ObjectId,
ref: "Project"
}
});
module.exports = mongoose.model("Image", ImageSchema);

Return the actual document instead of ObjectId

So, I have a model called Drivers that receive a field called "user", which references a document from another model, like this:
const DriversSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
},
{
timestamps: true,
}
);
// ...
Querying the collection works as expected, here's an example:
Drivers.find({});
// returns ->
[
{
"name": "John",
"user": "5e43f8ad2fbb1d0035d5a154",
}
]
Is there a way to return the actual document represented by the 'user' field?
Thanks!