i am unable to save mongodb data in array of documents - javascript

I Have created a Schema to store user Details and Some information regarding it's test.
const mongoose = require("mongoose");
const schema = mongoose.Schema;
const userSchema = new schema({
name: { type: String },
gender: { type: String },
stream: { type: String },
email: {
type: String,
required: true,
unique: true,
match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/,
},
verified: { type: Boolean, default: false },
password: { type: String, required: true },
// For premium Calculations
test: {
type1Count: { type: Number, default: 0 },
type2Count: { type: Number, default: 0 },
type3Count: { type: Number, default: 0 },
},
testCompleted: [
{
testId: { type: Number },
testDate: { type: Number },
testTypeNumber: { type: Number },
testTypeName: { type: String },
testDurationInMinutes: {type: Number},
listOfQuestionId: [{ type: String }],
listOfCorrectAnswer: [{ type: Number }],
listOfAnswerByUser: [{ type: Number }],
totalNumberOfQuestion: { type: Number, default: 0 },
numberOfAttemptedQuestion: { type: Number, default: 0 },
numberOfUnattemptedQuestion: { type: Number, default: 0 },
numberOfCorrectAnswer: { type: Number, default: 0 },
numberOfWrongAnswer: { type: Number, default: 0 },
marksObtained: {type: Number, default: 0 },
isTestCompleted : {type: Boolean, default: false}
},
]
});
module.exports = mongoose.model("User", userSchema);
Now, I am able to save half Data in the testCompletd array from this code ...
User.findOneAndUpdate(
{ _id: user._id}, // for Verification
{ $push:
{ testCompleted:
{
testId: Object.keys(user.testCompleted).length +1, // I choose Normal serialise Number starting from 1
testDate: Date.now(),
testTypeNumber: type,
testTypeName: testList[type - 1]["testName"],
testDurationInMinutes: testList[type - 1]["testDurationInMinutes"],
weightageOfQuestion: list[type - 1],
totalNumberOfQuestion: list[type - 1]["physics"] + list[type - 1]["chemistry"] + list[type - 1]["biology"],
listOfQuestionId: arrayOfQuestion,
listOfCorrectAnswer: arrayOfAnswer
}
}
}
)
Now, this will result a multiple insertions of data in the database like this ...when i hit the Routes 2 times...and That's work fine..
{
"_id" : ObjectId("5f436c5bf183fb93266a5574"),
"test" : {
"type1Count" : 0,
"type2Count" : 0,
"type3Count" : 0
},
"verified" : false,
"name" : "prince",
"email" : "kumar#gmail.com",
"password" : "$2a$10$RCVA2YNzKPjTJKDJhCfeZuqw83GnruQ4s9/7EhrkOs4JpuUVG2j9C",
"testCompleted" : [
{
"listOfQuestionId" : [
"5f3fc58aec2c8d59e5258625",
"5f3fc591ec2c8d59e5258636",
"5f3fc58cec2c8d59e525862a",
"5f3fc593ec2c8d59e525863a",
"5f3fc57bec2c8d59e5258617",
"5f3fc588ec2c8d59e5258622",
"5f3fc57cec2c8d59e5258619",
"5f3fc58aec2c8d59e5258626",
"5f3fc588ec2c8d59e5258621",
"5f3fc57dec2c8d59e525861a",
"5f3fc55cec2c8d59e52585f4",
"5f3fc56cec2c8d59e525860d",
"5f3fc55aec2c8d59e52585f1",
"5f3fc561ec2c8d59e52585fa",
"5f3fc568ec2c8d59e5258607",
"5f3fc55bec2c8d59e52585f2",
"5f3fc570ec2c8d59e5258614",
"5f3fc56fec2c8d59e5258612",
"5f3fc565ec2c8d59e5258601",
"5f3fc566ec2c8d59e5258603",
"5f3fc526ec2c8d59e52585a4",
"5f3fc545ec2c8d59e52585d2",
"5f3fc54dec2c8d59e52585e1",
"5f3fc54cec2c8d59e52585e0",
"5f3fc53fec2c8d59e52585c6",
"5f3fc549ec2c8d59e52585d9",
"5f3fc52eec2c8d59e52585ae",
"5f3fc52fec2c8d59e52585af",
"5f3fc554ec2c8d59e52585ed",
"5f3fc53bec2c8d59e52585c0",
"5f3fc52bec2c8d59e52585ac",
"5f3fc52eec2c8d59e52585ad",
"5f3fc542ec2c8d59e52585cb",
"5f3fc527ec2c8d59e52585a5",
"5f3fc54eec2c8d59e52585e3",
"5f3fc536ec2c8d59e52585b9",
"5f3fc546ec2c8d59e52585d4",
"5f3fc53dec2c8d59e52585c3",
"5f3141ed72d27d9df229dfe9",
"5f3fc54dec2c8d59e52585e2"
],
"listOfCorrectAnswer" : [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
4,
1
],
"listOfAnswerByUser" : [],
"totalNumberOfQuestion" : 40,
"numberOfAttemptedQuestion" : 0,
"numberOfUnattemptedQuestion" : 0,
"numberOfCorrectAnswer" : 0,
"numberOfWrongAnswer" : 0,
"marksObtained" : 0,
"isTestCompleted" : false,
"_id" : ObjectId("5f436c6ef183fb93266a5575"),
"testId" : 1,
"testDate" : 1598254190194.0,
"testTypeNumber" : 1,
"testTypeName" : "Minor",
"testDurationInMinutes" : 30
},
{
"listOfQuestionId" : [
"5f3fc58dec2c8d59e525862b",
"5f3fc586ec2c8d59e525861f",
"5f3fc58bec2c8d59e5258628",
"5f3fc58dec2c8d59e525862c",
"5f3fc58aec2c8d59e5258626",
"5f3fc592ec2c8d59e5258638",
"5f3fc591ec2c8d59e5258634",
"5f3fc590ec2c8d59e5258633",
"5f3fc591ec2c8d59e5258636",
"5f3fc58fec2c8d59e5258630",
"5f3fc562ec2c8d59e52585fd",
"5f3fc55eec2c8d59e52585f7",
"5f3fc565ec2c8d59e5258602",
"5f3fc570ec2c8d59e5258614",
"5f3fc571ec2c8d59e5258615",
"5f3fc55cec2c8d59e52585f3",
"5f3fc55aec2c8d59e52585f0",
"5f3fc56fec2c8d59e5258613",
"5f3fc55bec2c8d59e52585f2",
"5f3fc56eec2c8d59e5258611",
"5f3fc54eec2c8d59e52585e3",
"5f3fc549ec2c8d59e52585da",
"5f3fc53eec2c8d59e52585c5",
"5f3fc521ec2c8d59e52585a0",
"5f3fc53dec2c8d59e52585c3",
"5f3fc528ec2c8d59e52585a6",
"5f3fc538ec2c8d59e52585bc",
"5f3fc542ec2c8d59e52585cb",
"5f3fc528ec2c8d59e52585a7",
"5f3fc53cec2c8d59e52585c1",
"5f3fc543ec2c8d59e52585cd",
"5f3fc552ec2c8d59e52585eb",
"5f3fc543ec2c8d59e52585ce",
"5f3fc534ec2c8d59e52585b5",
"5f3fc53cec2c8d59e52585c2",
"5f3fc54cec2c8d59e52585df",
"5f3fc541ec2c8d59e52585ca",
"5f3fc542ec2c8d59e52585cc",
"5f3fc548ec2c8d59e52585d7",
"5f3fc549ec2c8d59e52585d9"
],
"listOfCorrectAnswer" : [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
],
"listOfAnswerByUser" : [],
"totalNumberOfQuestion" : 40,
"numberOfAttemptedQuestion" : 0,
"numberOfUnattemptedQuestion" : 0,
"numberOfCorrectAnswer" : 0,
"numberOfWrongAnswer" : 0,
"marksObtained" : 0,
"isTestCompleted" : false,
"_id" : ObjectId("5f436c7bf183fb93266a5576"),
"testId" : 2,
"testDate" : 1598254203550.0,
"testTypeNumber" : 1,
"testTypeName" : "Minor",
"testDurationInMinutes" : 30
}
],
"__v" : 0
}
Now, as you can see that, In my user model I have others field also in my testCompleted Section...like ..
listOfAnswerByUser: listOfAnswerByUser,
totalNumberOfQuestion: totalNumberOfQuestion,
numberOfAttemptedQuestion: attempt,
numberOfUnattemptedQuestion: totalNumberOfQuestion - attempt,
numberOfCorrectAnswer: attempt - wrong,
numberOfWrongAnswer: wrong,
marksObtained: marks,
isTestCompleted: true
Now, I want to save these data in a particular index of that array but it doesn't work please help me ...
I am trying like this but IT DOESN'T WORK.
User.findOneAndUpdate(
{ _id: user._id, "testCompleted.testId": 0}, // for Verification // 5f42cd4cf3a7458ddd4f5013
{ $push:
{ testCompleted:
{
testId: testId,
listOfAnswerByUser: listOfAnswerByUser,
totalNumberOfQuestion: totalNumberOfQuestion,
numberOfAttemptedQuestion: attempt,
numberOfUnattemptedQuestion: totalNumberOfQuestion - attempt,
numberOfCorrectAnswer: attempt - wrong,
numberOfWrongAnswer: wrong,
marksObtained: marks,
isTestCompleted: true
}
}
}
)

In order to update an array-element at a specific index, you can use the positional-operator in combination with $set:
User.findOneAndUpdate(
{_id: user._id, "testCompleted.testId": "<testId you want to update>"},
{
$set: {
"testCompleted.$": {
numberOfAttemptedQuestion: attempt,
numberOfUnattemptedQuestion: totalNumberOfQuestion - attempt,
numberOfCorrectAnswer: attempt - wrong,
numberOfWrongAnswer: wrong,
marksObtained: marks,
isTestCompleted: true
}
}
}
)

Related

Filter data from array in array mongo

I have this data structure:
{
date: 0,
darwin: [
{
d: ['string1', 1, 0, 0, 0]
},
{
d: ['string2', 1, 0, 0, 0]
},
{
d: ['string3', 1, 0, 0, 0]
}
]
}
and this schema:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const dataSchema = new Schema({
date: { type: Number, required: false, unique: true, index: true },
humanDate: { type: Date, required: false },
darwin: [
{
d: {
type: Array,
required: false
}
}
]
});
module.exports = mongoose.model('data', dataSchema);
I need a list of strings inside "d", i try this
db.getCollection('data').find({date:0},{'darwin.d.$': 1})
but i have this error
Error: error: {
"operationTime" : Timestamp(1635348468, 1),
"ok" : 0,
"errmsg" : "positional operator '.$' couldn't find a matching element in the array",
"code" : 51246,
"codeName" : "Location51246",
"$clusterTime" : {
"clusterTime" : Timestamp(1635348468, 1),
"signature" : {
"hash" : BinData(0,"pfgMUIJkpgjlfnQ6cfiEDpSY+3o="),
"keyId" : NumberLong("7020434099001098244")
}
}}
I have tried several things but I can't get it to get the list of strings, I don't know if I'm applying the '$' operator wrong
I expected some like this
{
date: 0,
darwin: [
{
d: 'string1'
},
{
d: 'string2'
},
{
d: 'string3'
}
]
}
You can use aggregate method like this:
First $match the docuemnts where date has the desired value
Then $project to map over the array and get values you want: For each element in darwin array get the first element in d array using $arrayElemAt.
db.collection.aggregate([
{
"$match": {
"date": 0
}
},
{
"$project": {
"_id": 0,
"date": 1,
"darwin": {
"$map": {
"input": "$darwin",
"as": "m",
"in": {
"d": {
"$arrayElemAt": [
"$$m.d",
0
]
}
}
}
}
}
}
])
Which output is:
[
{
"darwin": [
{
"d": "string1"
},
{
"d": "string2"
},
{
"d": "string3"
}
],
"date": 0
}
]
Example here

Grouping array of objects by multiple properties

I have an array of notifications that I want to group by certain conditions (like facebook's notifications)
var data = [
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' },
]
Let's say I want to group by date in descending order
So I have this code:
function sortByDate(array, desc = true) {
if (desc === false) {
// Ascending order
return array.sort((a, b) => {
if (new Date(a.created_at) > new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
// Descending order
return array.sort((a, b) => {
if (new Date(a.created_at) < new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
So now we have array like this:
[
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
]
Now that our array is sorted, I created a function:
// https://www.tutorialspoint.com/most-efficient-method-to-groupby-on-an-array-of-objects-in-javascript
function groupByProperty(array, property) {
return array.reduce((acc, object) => {
const key = object[property]
if (! acc[key]) {
acc[key] = []
}
acc[key].push(object)
return acc
}, {})
}
Then, I run this code
Object.values(groupByProperty(data, 'type'))
Which return:
[
[
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' }
],
[
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' }
],
[
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' }
],
[
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' }
],
]
I want to group these notifications by these categories:
Same type (I already covered this in my function groupByProperty())
Same in: { id: ... } Except for type: shop.follower
If #1 and #2 were true, check for similar objects with created_at: ... date interval between 10 minutes
If we have a case like #3 (multiple), if one among it has read_at = null, then it will be an unread notification, get the latest (newest) date
In id: 4 and id: 5, interval between timestamp are less than 10 minutes, so I want it to group as one
example EXPECTED OUTPUT:
[
[
{ by: {id: 4, name: "User D"}, created_at: "2021-07-24 08:34:25", id: 8, in: {id: 6}, read_at: null, type: "comment.replied" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-07-18 10:31:12", id: 7, in: null, read_at: null, type: "shop.follower" }
],
[
{ by: {id: 5, name: "User E"}, created_at: "2021-05-23 10:02:21", id: 6, in: null, read_at: null, type: "shop.follower" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-03-28 08:12:24", id: 5, in: {id: 1}, read_at: null, type: "product.liked" },
{ by: {id: 4, name: "User D"}, created_at: "2021-03-28 08:11:50", id: 4, in: {id: 1}, read_at: "2021-03-29 15:14:21", type: "product.liked" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-02-19 16:21:43", id: 3, in: {id: 1}, read_at: "2021-02-20 20:01:39", type: "product.commented" }
],
[
{ by: {id: 2, name: "User B"}, created_at: "2020-08-02 05:24:45", id: 2, in: {id: 1}, read_at: "2021-01-03 10:15:43", type: "product.liked" }
],
[
{ by: {id: 2, name: "User B"}, created_at: "2020-08-02 05:21:20", id: 1, in: null, read_at: "2021-01-03 10:15:43", type: "shop.follower" }
],
]
example IN BROWSER:
|------------------------------------------------------------------------------|
| - (UNREAD) User D replied to your comment ....., 2021-07-24 08:34:25 |
| - (UNREAD) User C start follow your shops ....., 2021-07-18 10:31:12 |
| - (UNREAD) User E start follow your shops ....., 2021-05-23 10:02:21 |
| - (UNREAD) User C and D liked your product ....., 2021-03-28 08:12:24 | <= (Please pay attention)
| - (READ) User C commented on your product ....., 2021-02-19 16:21:43 |
| - (READ) User B liked your product ....., 2020-08-02 05:24:45 |
| - (READ) User B start follow your shops ....., 2020-08-02 05:21:20 |
This is the code I tried to find interval between 10 minutes
function inRangeBetween(val, min, max) {
if (val >= min && val <= max) {
return true
}
return false
}
var startingPoint = { min: 0, max: 0, type: null },
newData = []
for (var i = 0; i < data.length; i++) {
if (startingPoint.min < 1
&& startingPoint.max < 1
&& startingPoint.type === null) {
console.log('Starting point')
var start = new Date(data[i].created_at)
startingPoint.min = start.getTime()
startingPoint.max = start.getTime() + (10 * 60000)
startingPoint.type = data[i].type
newData[data[i].type] = []
} else {
// startingPoint has values
if (inRangeBetween(new Date(data[i].created_at).getTime(), startingPoint.min, startingPoint.max
&& data[i].type === startingPoint.type) {
console.log(`Pushing new object to key ${data[i].type}`)
newData[data[i].type].push(data[i])
} else {
// Set new values for startingPoint, and start again comparing
console.log('Starting point values changes')
startingPoint.min = new Date(data[i]).getTime()
startingPoint.min = new Date(data[i]).getTime() + (10 * 60000)
startingPoint.type = data[i].type
newData[data[i].type] = []
newData[data[i].type].push(data[i])
}
}
}
// Not working
How to achieve this? (Stuck in this problem for 5 days)
Thanks in advance
Try like this:
var data = [
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1 }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1 }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1 }, read_at: '2021-01-03 10:15:43', created_at: '2021-03-28 08:11:50' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1 }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6 }, read_at: null, created_at: '2021-07-24 08:34:25' }
]
function sortByDate(array, desc = true) {
if (desc === false) {
// Ascending order
return array.sort((a, b) => {
if (new Date(a.created_at) > new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
// Descending order
return array.sort((a, b) => {
if (new Date(a.created_at) < new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
function groupByProperties(array, properties) {
return Object.values(array.reduce((acc, object) => {
const key = properties.reduce((acc, property) => {
return acc + (object[property] ? JSON.stringify(object[property]) : '')
}, '')
if (! acc[key]) {
acc[key] = []
}
acc[key].push(object)
return acc
}, {}))
}
function groupByInterval(data, interval) {
var group;
for(var i = 0; i < data.length; i++) {
if(1 < data[i].length) {
var max_date = new Date(data[i][0].created_at);
for(var j = data[i].length - 1; 0 < j; j--) {
var next_date = new Date(data[i][j].created_at)
if(interval < max_date - next_date) {
if(!group) {
group = i + 1;
data.splice(group, 0, [])
}
data[group].splice(0, 0, data[i][j])
data[i].splice(j, 1)
};
};
if(group) {
return groupByInterval(data, interval)
};
}
data[i].sort((a, b) => {
if(!a.read_at) {
return -1
}
if(!b.read_at) {
return 1
}
return 0
})
}
data.sort((a, b) => new Date(b[0].created_at) - new Date(a[0].created_at))
return data
}
sortByDate(data)
//1. Same type
//2. Same in: { id: ... } (Except for type: shop.follower)
data = groupByProperties(data, ['type', 'in'])
//3. If #1 and #2 true, check for similar objects with created_at: ... date gap between 10 minutes
//4. If we have a case like #3 (multiple), if one among it has read_at = null, then it unread notification, then get the latest (newest) date
data = groupByInterval(data, 1000 * 60 * 10) //10min
console.log(data)
groupByProperties() is based on groupByProperty(), but accepts multiple properties for grouping (categories 1 and 2). It checks whether the value of the property is falsy (such as null), excluding it from grouping criteria if so.
groupByInterval() added to separate groups according to a specified interval in milliseconds (categories 3 and 4). It then sorts the groups according to read_at being falsy, so that objects with read_at == null appear first in each group. It then sorts across groups to achieve the order in the expected result.
Mr.sbgib is absolutely correct, but i just modified sortByDate function to a little short as follows to reduce duplicate codes,
function sortByDate(array, desc = true) {
return array.sort((a, b) => {
var compare = new Date(a.created_at) < new Date(b.created_at);
return (desc == true) ? ((compare == true) ? 1 : -1) : ((compare == false) ? 1 : -1);
})
}

sort an array by a boolean property in typescript

I am using angular 10 and I was wondering how can I sort this array
var dic = [
{ state: false, id: 1 },
{ state: true, id: 2} ,
{ state: false, id: 3 },
{ state: true, id: 4 },
{ state: false, id: 5 }
]
I want to sort by the value of the boolean state, so the result goes this way:
[
{ state: true, id: 2 },
{ state: true, id: 4 },
{ state: false, id: 1 },
{ state: false, id: 3 },
{ state: false, id: 5 }
]
The true value goes first in the array.
What property or something from typescript I have to use to do that?
Thank you!
You can do this using Array#sort by converting the boolean values of state:
Number(true) //1
Number(false) //0
const dic = [
{ state: false, id: 1 },
{ state: true, id: 2 },
{ state: false, id: 3 },
{ state: true, id: 4 },
{ state: false, id: 5 }
];
dic.sort(({ state: stateA = false }, { state: stateB = false }) =>
Number(stateB) - Number(stateA)
);
console.log(dic);
You can complete it by doing simplify like this.
dic.sort((a, b) => b.state - a.state);
Explain:
We all know that:
false // 0
true // 1
So
false - true // -1
true - false // 1
true - true // 0
false - false // 0
Demo
const dic = [
{ state: false, id: 1 },
{ state: true, id: 2 },
{ state: false, id: 3 },
{ state: true, id: 4 },
{ state: false, id: 5 }
];
dic.sort((a, b) => b.state - a.state);
console.log(dic);
You can sort by the state by casting the boolean to an integer value of 1 or 0 by appending a double-bang (!!) or double-tilde (~~). If the result is 0, move onto the id values.
const dic = [
{ state: false , id: 1 },
{ state: true , id: 2 },
{ state: false , id: 3 },
{ state: true , id: 4 },
{ state: false , id: 5 }
];
dic.sort(({ state: stateA, id: idA }, { state: stateB, id: idB }) =>
(!!stateB - !!stateA) || (idA - idB));
console.log(dic);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Alternatively:
(~~stateB - ~~stateA) || (idA - idB)

Trying to get data from Mongo DB with aggregate

I have "Offers" and "Requests" collections, I need to get all offers that user made, group them by requests and find the lowest "Offer.price" on each request, each offer has requestId field.
I am using aggregate to solve this,
db.Offer.aggregate([{
$match: {
ownerId: mongoose.Types.ObjectId(req.params.ownerId)
}
},
{
$group: {
_id: "$requestId",
price: {
$min: "$price"
}
}
}
])
and This is what i get :
[ { _id: 5dc47241af1406031489c65c, price: 14 },
{ _id: 5dc47241af1406031489c653, price: 3 },
{ _id: 5dc47241af1406031489c656, price: 5 },
{ _id: 5dc8add63f73953ff408f962, price: 6 },
{ _id: 5dc8add63f73953ff408f969, price: 22 },
{ _id: 5dc47241af1406031489c658, price: 1 } ]
Now I want to populate these with rest of the data from "Offer"
const OfferSchema = new Schema({
requestId: {
type: Schema.Types.ObjectId,
ref: 'Request'
},
ownerId: {
type: Schema.Types.ObjectId,
required: true,
ref: 'User'
},
price: {
type: Number,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
isBest: {
type: Boolean,
default: false
},
isWinner: {
type: Boolean,
default: false,
}
});
What would be best way to do something like this?
Thank you for your help!
Consider the following dataset:
db.dum.insert({ownerId:1, requestId:'a', price:3, createdAt:3, isWinner:true})
db.dum.insert({ownerId:1, requestId:'a', price:1, createdAt:1, isWinner:false})
db.dum.insert({ownerId:1, requestId:'a', price:2, createdAt:2, isWinner:true})
db.dum.insert({ownerId:1, requestId:'b', price:4, createdAt:2, isWinner:true})
db.dum.insert({ownerId:1, requestId:'b', price:5, createdAt:1, isWinner:false})
db.dum.insert({ownerId:2, requestId:'b', price:5, createdAt:1, isWinner:false})
You could use $reduce
Here, for a grouping id, we keep all matching documents as an array (candidates).
On the project stage, for each group we iterate through the array, and reduce it to the minimal element found (by price that is)
db.dum.aggregate([{
$match: {
ownerId: 1
}
},
{
$group: {
_id: "$requestId",
candidates: { $push:'$$ROOT'}
}
},
{
$project:{
item: {
$reduce: {
input: '$candidates',
initialValue: '$candidates.0',
in: {
$cond: {
if: {
$lt: ['$$value.price', '$$this.price']
},
then:'$$value',
else:'$$this'
}
}
}
}
}
},
{
$replaceRoot:{newRoot:'$item'}
}
]).toArray()
output:
[
{
"_id" : ObjectId("5ddcc8e0eb1f0217802fb507"),
"ownerId" : 1,
"requestId" : "b",
"price" : 4,
"createdAt" : 2,
"isWinner" : true
},
{
"_id" : ObjectId("5ddcc8e0eb1f0217802fb505"),
"ownerId" : 1,
"requestId" : "a",
"price" : 1,
"createdAt" : 1,
"isWinner" : false
}
]

Why is no document returned while querying a sub-doc in Mongoose?

I am running the following code:
var oid = new mongoose.Types.ObjectId(req.params.id);
req.query = {
toId : {
id: oid
},
deleted : false
};
X.find(req.query, function (err, docs){
if(!err){
res.status(responses.ok.status).json(docs);
}
else{
return next(errorHelper(err));
}
}).select(visibleFields.X);
I would like to query the X model by its toId.id field. toId field is of type Y. Here are the model definitions:
var X = new Schema({
deleted: {
type: Boolean,
required: true,
default: false
},
toId: {
type: entityId,
required: true
}
});
Y is just an object defined as:
var Y = {
id: {
type: Schema.Types.ObjectId,
required: true
},
entityName:{
type: String,
required: true,
enum: entityTypeList
}
};
In my database, I have an entry like:
{
"_id" : ObjectId("55d1f4fddaea17d3e90a3c55"),
"toId" : {
"id" : ObjectId("55dde27a0f6ff71b72dc7981"),
"entity" : "user"
},
"deleted" : false
}
which should, by all means, satisfy my criteria.
However, the following query:
messages.find({ deleted: false, toId: { id: ObjectId("55dde27a0f6ff71b72dc7981") } }) { fields: { messageType: 1, toId: 1, timesOff: 1, role: 1, read: 1, productId: 1, participantId: 1, oldRole: 1, message: 1, memberId: 1, lessonId: 1, important: 1, fromId: 1, formerInstructorId: 1, timestamp: 1, changedFields: 1, bookerId: 1, assignedInstructorId: 1, accepted: 1, _id: 1 } }
returns an empty list. Why is that happening?
Try a query like this:
req.query = {
"toId.id": oid,
deleted : false
};

Categories

Resources