crosstab-query or virtuals to save data using mongoose - node.js

I have a json object which i like to save in mongodb,
{
"user": "abc",
"week": 21,
"year": 2021
"data": [
{
"date": "01/01/21",
"present": true
},
{
"date": "02/01/21",
"present": false
}
]
}
this has to be split into 2 tables: timesheet-main and timesheet-data
timesheet-main.model will be like this:
{
"user": "abc",
"week": 21,
"year": 2021,
data: {
ref: timesheet-data.model
}
}
AND timesheet-data.model will be like this:
{
{
user: userIdFrom-timesheet-main.model,
timesheet-main-id: timesheet-main-ref-from-above-collection,
"date": "02/01/21",
"present": false
}
}
so that when I want week wise user query, i get result like this:
{
"_id": "asf5sf44sdw3sfsf",
"user": "abc",
"week": 21,
"year": 2021
"data": [
{
"_id": "Asdfsdfsdfsdfsdfsf",
"date": "01/01/21",
"present": true
},
{
"_id": "egdfgfhfghfghfgh"
"date": "02/01/21",
"present": false
}
]
}
I dont know any good or easy way of doing this, so while saving data in timesheet-main.model, after its success, i am calling another insert into timesheet-data.model, and saving data in this. But someone suggeted that there can be better way of doing this using Virtuals. I tried but no success.
Any help/suggestion is highly appreciated.
Thanks

You are looking to implement a one-to-many relationship in mongo. You could follow on this link.
As for the model:
timesheet-main.model [Parent]
{
"data": [{ type: Schema.Types.ObjectId, ref: timesheet-data.model }]
}
timesheet-data.model [Child]
{
"timesheet-main-id": { type: Schema.Types.ObjectId, ref: timesheet-main.model },
}
Consider additional fields as per choice. I am only adding fields for a one-to-many relationship.
For adding data -
const parent = new TimesheetMain({
_id: new mongoose.Types.ObjectId(),
data: []
})
const child = new TimesheetData()
child.timesheet-main-id = parent._id
child.save(err => HandlerErr)
parent.data.push(child)
parent.save(err=> HandlerErr)

Related

Mongoose return unique documents with count while using populate

I have a collection that will store multiple copies of the same data
Is there a way in mongoose to return all the unique records based on a certain field, and additionally provide the count field with each object, while using populate to get the full document?
A simple example is something like this:
Lets say the data in my collection looks like this:
[
{
person: ObjectId("123"),
data: 'this will be random data',
_id: ObjectId("xxx")
},
{
person: ObjectId("456"),
data: 'this will be random data',
_id: ObjectId("xxx")
},
{
person: ObjectId("123"),
data: 'this will be random data',
_id: ObjectId("xxx")
}
]
Since I dont want the data field, because this data is random, and I only want a count of the unique documents, my query looks like this:
Model.find().select({'person':1})
Now I only have the person field and _id.
Now I want to populate the data, so my query looks like this:
Model.find().select({'person':1}).populate('person')
Then I get data like this:
[
{
name: 'Jim',
salary: '200'
},
{
name: 'Mike',
salary: '150'
},
{
name: 'Jim',
salary: '200'
},
]
Now what I finally want to get is something like this:
[
{
name: 'Jim',
salary: '200',
count: 2
},
{
name: 'Mike',
salary: '150',
count: 1
},
]
All the random fields have been removed, and I only get a single, populated document with a count for each unique type. in this case, the name field is used as the distinct field.
So far I could not yet get this to work while using populate. Is this possible to achieve with mongoose, or will it require some manual computation?
You might want to use a virtual populate:
Person model:
const personSchema = new mongoose.Schema(
{
name: String,
},
{
// this is needed to display the virtual in json format, like res.json()
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
personSchema.virtual("count", {
ref: "Task",
localField: "_id",
foreignField: "person",
count: true,
});
Task model:
const taskSchema = mongoose.Schema({
person: { type: mongoose.Schema.Types.ObjectId, ref: "Person" },
data: String,
});
instead of searching by task model, you can search by people model
const persons = await personModel.find().select("-_id").populate("count");
Person collection:
{
"_id": "639222fa3f87b88812e95d1d",
"name": "jonh",
"__v": 0,
},
{
"_id": "639222fffcd0793b0580302e",
"name": "joseph",
"__v": 0,
}
Tasks collection:
{
"_id": "6392231815cd8663c5671edf",
"person": "639222fffcd0793b0580302e",
"data": "some data",
},
{
"_id": "6392231a15cd8663c5671ee1",
"person": "639222fffcd0793b0580302e",
"data": "some data",
},
{
"_id": "639223337409d3e1a1f741ac",
"person": "639222fa3f87b88812e95d1d",
"data": "some data",
}
and the result of the query:
[
{
"_id": "639222fa3f87b88812e95d1d",
"name": "jonh",
"count": 1,
"id": "639222fa3f87b88812e95d1d"
},
{
"_id": "639222fffcd0793b0580302e",
"name": "joseph",
"count": 2,
"id": "639222fffcd0793b0580302e"
}
]
"id" field is added for toJSON: { virtuals: true }, you can ignore it.
I hope it helps you, here the docs: enter link description here

How to use $pull to delete a particular data from a document in mongoDB

I'm pretty new in MongoDB,I want to delete a particular object from an array of objects in a document. I tried a lot and finds a lot of questions in StackOverflow.But none of them worked (maybe it's my fault)
following is a document from a collection that is matched by the user with userId
61f15af01a3c53dfa87e38e6
The Document
{
"_id": "61f15af01a3c53dfa87e38ed",
"user": "61f15af01a3c53dfa87e38e6",
"transactions": [
{
"amount": 50,
"category": "Bills",
"type": "Expense",
"_id": "61f15af01a3c53dfa87e38ee"
},
{
"amount": 100,
"category": "Lottery",
"type": "Income",
"_id": "61f15af01a3c53dfa87e38ef"
},
{
"amount": 200,
"category": "Salary",
"type": "Income",
"_id": "61f15af01a3c53dfa87e38f0"
},
]
}
I want to delete the transaction with an Id of 61f15af01a3c53dfa87e38ef
I tried the below one (I don't know whether it is correct)
const allTransactions = await Transactions.findOne({ user: req.user._id });
const updatedTransactions = await allTransactions.update(
{ },
{ $pull: { transactions: { id: req.params.id } } },
);
Can anyone Spot the mistake and how can I achieve it ?
Thanks in advance :)
You can do it in one database call using below statement:
await Transactions.update(
{ user: "61f15af01a3c53dfa87e38e6" },
{ $pull: { "transactions": { _id: "61f15af01a3c53dfa87e38f0" } } }
)
Mongo Playground
Also make sure types match. If _id is of type ObjectId instead of string you should convert req.params.id to ObjectId first. See below:
await Transactions.update(
{ user: mongoose.Types.ObjectId(req.user._id) },
{ $pull: { "transactions": { _id: mongoose.Types.ObjectId(req.params.id) } } }
)

Replace array of objects with another in Mongo DB

I need to replace members array data with new array of objects mems given below.
{
"name": "Test Group",
"members": [{
'userId': {
$oid: 'fjkfkffy'
},
name: 'Himanshu'
}],
"athletes": [],
"leads": []
}
Here I want to replace members array of object with new array of objects. I basically need to overwrite that members array. I've been trying to do something like this below, but I got an error. Can anyone please help me out?
const mems = [{
"user": {
"$oid": "6093a4a709cc0b000d31ber8",
},
"role": "manager"
},
{
"user": {
"$oid": "60a3aea6ecbf4398f01aa598"
},
"role": "user"
}
];
entities.findOneAndUpdate({
_id: ObjectID(entityID),
"groups._id": ObjectID(groupID)
}, {
$set: {
'groups.$.name': name,
'groups.$.members': mems
}
}, {
'new': true
});

Scope Results in mongoose by date

I'm having a hard time trying to achieve this results for days. I hope someone can help me here.
Results I want to achieve. Btw I'm using mongoose/mongodb/node.js
{
"2020-01-12": [
{
"user_id": 1234,
"firstName": "John Doe"
"createdAt": 2021-01-12T05:45:50.898Z
},
{
"user_id": 1233,
"firstName" "Jane Doe",
"createdAt": 2021-01-12T06:45:50.898Z
}
],
"2020-01-13": [
{
"user_id": 1232,
"firstName" "Jeff Doe",
"createdAt" 2021-01-13T05:45:50.898Z
}
]
}
My sample schema
const User = {
table: 'User',
schema: {
_id: {
name : 'Id',
type: db.keyType(),
required: true
},
firstName: {
name: 'FirstName',
type: String,
required: true,
}
}
Here's my sample code.
Users.find({ createdAt: { $gte: startDate, $lte: endDate.setHours(endDate.getHours() + 23) }}).sort({ createdAt: 'asc'}).then(results => {
res.status(200).json({
results
})
URL: api/users/days/?start_date=2021/01/12&end_date=2021/01/15
I want to scope my data by date but I can't achieve it using mongoose. Thanks in advance if you can help me with this. Its okay if you can help me understand the logic on how to achieve so I can fully understand what I need to learn to get this results so I can research for it. ty very much
Also my **date format is like this ** 2021-01-13T05:45:50.898Z

How to get an object field as an array in mongoose?

Hello I have a mongoose schema like the following,
const followingFollowersSchema = mongoose.Schema({
follower: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
following: {
type: mongoose.Schema.ObjectId,
ref: 'User'
},
});
I have created a route when called it filters all the users that the current logged in user is following and shows the following output,
{
"status": "success",
"results": 1,
"data": {
"following": [
{
"_id": "5ef4cd0205070d87156e19da",
"following": {
"_id": "5eeb92d69fceed6d91ad5743",
"name": "X Y"
}
}
]
}
}
But I want to show the output like this,
{
"status": "success",
"results": 1,
"data": {
"following": [
{
"_id": "5eeb92d69fceed6d91ad5743",
"name": "X Y"
}
]
}
}
How can I accomplish this? Any help would be appreciated.
You can use $addFields to replace existing fields and $map to transform an inner array:
let result = Model.aggregate([
{
$addFields: {
"data.following": {
$map: {
input: "$data.following",
in: "$$this.following"
}
}
}
}
])
Mongo Playground

Resources