Mongoose - Ref - update parent based on child document - mongodb

Instead of having sub-documents, as these schemas/models are queried a lot and independently, I decided to use "Ref" feature of Mongoose. The use case is a Job holding multiple Requests, so I have a Job schema and a Request schema like below..
const jobSchema = new Schema({
_id: {
type: Schema.Types.UUID,
},
status: {
type: String,
enum: _.keys(jobStatus),
},
requestIds: [
{
type: Schema.Types.UUID,
ref: 'Request',
},
],
});
and
const request = new Schema({
_id: {
type: Schema.Types.UUID,
},
jobId: {
type: Schema.Types.UUID,
ref: 'Job',
},
status: {
type: String,
enum: _.keys(requestStatus),
},
});
The request status are updated independently, but the job status is dependent on the completion of the request status. So, if all the requests are completed, i need to mark the job status as completed. In order to update the job to Completed, i need to look at if all the requests Ids are having the status to completed.
How do I do in Mongoose query/ update, preferably, a single call to the database.

Related

How to navigate through documents in a circuler linked list fashion in MongoDB?

I have a really simple User model.
const userSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
address: {
type: String,
default: null,
},
description: {
type: String,
default: null,
},
active: {
type: Boolean,
default: true,
},
interests: [
{
type: String,
default: null,
},
],
favorites: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
default: null,
},
],
});
I have a use-case where the client should be able to navigate through the users one by one in a circular fashion. I was able to implement the functionality for getting the next and previous user relative to a specific user through the
this answer.
However, the issue with this is that if I try to get the previous document on the first document in the Users collection, it of course returns an empty object. And same is the case when I try to get the next document on the last document.
I want to tweak it so that if I try to get the previous document on the first document, it would return me the last document, and if I try to get the next document on the last document, it would return me the first document. Just like how you traverse through a circular linked list. Any help would be appreciated! Thanks.

Optimizing query that makes 3 API calls to the MongoDB server

const user_schema = mongoose.Schema(
{
user_name: {
type: String,
required: true,
},
},
{
collection: `user`,
timestamps: true,
}
);
const test_schema = mongoose.Schema(
{
test_name: {
type: String,
required: true,
},
},
{
collection: `test`,
timestamps: true,
}
);
const score_schema = mongoose.Schema(
{
user_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: true,
},
test_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "test",
required: true,
},
test_score: {
type: Number,
required: true,
},
},
{
collection: `score`,
timestamps: true,
}
);
query:
Given an array of user_id and an array of test_id, query the score model to find out the test scores.
To get the array of user_id, a set of conditions is given and the user model must be queried to find the set of users matching the conditions.
To get the array of test_id, a set of conditions is given and the test model must be queried to find the set of tests matching the conditions.
What needs to be done:
Make one query request to the MongoDB server to get the array of user_id.
Make a separate query request to the MongoDB server to get the array of test_id.
Make another query request to the MongoDB server to get the test scores:
db.getCollection("score").aggregate([
{$match: {$and: {user_id: {$in: array_of_user_id}, {test_id: {$in: array_of_test_id}}}}}
])
Is this the most optimal way to get the test scores? Is it possible to make just one request to the MongoDB server?

Documents inserted without schema not being found with schema

I have two new collections in MongoDB of data that I pulled from an old Firestore database that I'm moving to mongo. Since the total number between these two collections is roughly 20,000, I opted to paste the raw JSON into the insert document section in mongo, which worked like a charm and I didn't have to write a new insert route to do the same.
I then created a schema in Mongoose that matched the inserted documents, and tried to use the schema to pull back some data, and its always returning nothing.
An example of a ticket inserted via JSON:
{
"title": "How to add and manage users for your company in QuickBooks Online",
"priority": "1",
"type": "Video",
"course": "G205",
"transcriptId": "07dom27Zz98jakvB1oh5",
"status": "In Review",
"tags": "",
"url": "",
"revisionNumber": 0,
"directoryId": 19,
"checkedOut": false
},
And my schema I made to match. The collection name in mongo is also called oldTickets, the plural of my schema name here:
const mongoose = require('mongoose');
var Schema = mongoose.Schema
const schema = new Schema({
course: { type: String },
title: { type: String },
priority: { type: String },
type: { type: String },
course: { type: String },
transcriptId: { type: String },
status: { type: String },
tags: { type: String },
url: { type: String },
revisionNumber: { type: Number },
directoryId: { type: Number },
checkedOut: { type: Boolean },
});
module.exports = mongoose.model('oldTicket', schema);
And finally my model import and fetch call:
const OldTicket = require('./models/model_old_ticket');
/***************************************************************************
* Get Old Tickets - Returns all old tickets, 10 at a time
****************************************************************************/
app.get('/getOldTickets/:offset', (req, res) => {
checkConnection();
OldTicket.find().skip(parseInt(req.params.offset)).limit(10).exec((err, data) => {
if (err){ res.status(500).send({err: err}); }
//If we got data, count the tickets & return the tickets & count
if (data) {
OldTicket.find().countDocuments().then(count => {
return res.status(200).send({
tickets: data,
count: count
})
})
}
});
});
Why isn't this finding anything? Both the count and the tickets are 0. I've run into this issue before when manually creating a collection without a schema, and in those instances I would simply delete the collection, write a route to create a document, and then things would work fine. But with the large data size of these two collections, I'd rather not do that since everything should be working as is.
Edit: Example of document in Mongo
And the name of the collection I'm currently viewing:
And I just now realized that for some reason there are now two collection names, oldTickets, which has data, and oldtickets, which is empty. I'm assuming my query is searching through the empty one? How can I get it to go to the one that actually has data?
can you attach the screenshot of your data with the collection? might be it's different.in mongoose, every collection name is complete with 's'. please verify your collection is created manually by you then it has to same as mongoose schema and also completed with 's'.
example:
const mongoose = require("mongoose");
const schema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
index: true
},
filmId: {
type: mongoose.Schema.Types.ObjectId,
index: true
},
filmType: {
type: String,
index: true
},
birthday: {
type: Date
},
age: {
type: Number
},
terms: {
type: Boolean
}
},
{
versionKey: false,
timestamps: true,
}
);
schema.index({ filmId: 1, user: 1 })
module.exports = mongoose.model("UserAgeVerification", schema);
see my database

How to give iDs to dynamic fields in React-Redux?

I created a simple dynamic fields in React-Redux with a plus button to add as many field as I want (hobbies) of an already existing form. I'm using mongodb as a database and so I have this error that tells me that my fields/data don't have iDs.
so how can I generate iDs for my data?
this below is my model with featherJs. as you can see this is how I added my hobbies array in the existing model called myService. I can see that my hobbies are created in mongo (using Robo 3T) which is great but i'm having difficulty reusing them (hobbies) in an other component in Redux. I'm not sure if I should give IDs to this fields or create a new service just for them. I never coded something in backend so I'm confused. what's the rule for this kind of situations.
Any other suggestions would be helpful.
warning in Redux: Each child in a list should have a unique "key" prop.
error in api : Cast to ObjectId failed for value at path "_id" for model "
const { Schema } = mongooseClient;
const myService = new Schema({
type: { type: String, enum: VALID_TYPES, required: true },
user: {
type: mongooseClient.Schema.Types.ObjectId,
ref: 'user',
required: true
},
comment: String,
hobbies: [{
type: mongooseClient.Schema.Types.ObjectId,
ref: 'hobbies',
default: [],
required: false }],
date: {
begin: { type: Date, default: Date.now },
current: { type: Date, default: Date.now },
end: { type: Date, required: true },
},
}, {
timestamps: true
});
return mongooseClient.model('myService', myService);
};

Creating a many-to-many relationship in MongoDB/ Mogoose using nested fields?

I'm currently trying to wrap my head around creating a many-to-many relationship in mongodb/mongoose.
I have two Schemas:
// User Schema
var UserSchema = mongoose.Schema({
email: {
type: String,
index:true
},
name: {
type: String
},
tasks:[{type:mongoose.Schema.ObjectId, ref: 'Tasks'}]
});
and
// Tasks Schema
var TaskSchema = mongoose.Schema({
name: {
type: String,
index: true
},
description: {
type: String
},
status:{
type: String
},
});
The idea here, is that each user can take on a task and the task would have it's own status for each user (e.g. notStarted, inProgress, Complete, Failed). This status would change as the user progresses through the task. Each user would see the same tasks(i.e. name + description), but would have a different status associated with it. Additionally, each task has it's own status (Available, Hidden), which would dictate if the users can see the task or not. This would not be unique for each user.
This is my thought process so far:
I'm thinking that I can nest the objectIds of every task in with the user along with the status. For example:
{
email: "Bob#bob.com"
name: "Bob",
tasks: {
{ _id: 001, status: "Active"},
{_id: 002, status: "inProgress"},
{ _id: 003, status: "Failed"}
}
},
{
email: "Mary#mary.com"
name: "Mary",
tasks: {
{ _id: 001, status: "Failed"},
{ _id: 002, status: "Active"},
{ _id: 003, status: "Active"}
}
}
However, this means that whenever I create a new task, I need to add it to the task list of all users, with the status set to a default (e.g. notStarted). Additionally whenever I add a new user, I need to get all tasks and add them to the user's list of tasks.
This seems sort of clunky to me, and I feel like there must be a better way. If this is the best way to do it, I'm not quite sure what I would use to write this. I was thinking maybe use addFields or would Push be more appropriate? Or would that create arrays that grow without bound? which might not be the best idea since it's a Mongo anti-pattern from what I've read?
I also found this post that's sort of related, but it's from ~6 years ago, and I think I need a little bit more depth or code examples.
Any help would be much appreciated!
If you want to add new task in user whenever new task will created then your query should be :
taskCtr.create = (req, res) => {
const {
name,
description,
status
} = req.body;
TaskSchema.create({
name,
description,
status
}).then((result) => {
if (result) {
UserSchema.update({}, {
$push: {
tasks: {
_id: result._id,
status: result.status
}
}
}, {
multi: true
}).then((userUpdated) => {
res.status(200).json({
message: 'A new Task created successfully!'
})
}).catch((err) => {
res.status(500).json({
error: 'Internal server error!'
});
});
}
}).catch((err) => {
res.status(500).json({
error: 'Internal server error!'
});
});
};