Better way to achieve desired results for the following code - javascript

So the scenario is that I have this following array as my input:
[
{
"failureMessage": "failed",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4855"
}
},
"testSetName": "search"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4856"
}
},
"testSetName": "download"
},
{
"failureMessage": "failed 2",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4857"
}
},
"testSetName": "search"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4858"
}
},
"testSetName": "download"
},
{
"failureMessage": "failed",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4859"
}
},
"testSetName": "backgrounds"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4860"
}
},
"testSetName": "backgrounds"
}
]
the above array contains objects which hold the data regarding test cases
And I want an array like this:
[
{
"testSetName": "search",
"testCases": ["KEY-4855", "KEY-4857"]
},
{
"testSetName": "download",
"testCases": ["KEY-4856", "KEY-4858"]
},...
]
The above array contains objects and those objects hold the name of the test set(testSetName) and all the test cases which are part of this test set as testCases.
Now, my code is below:
let results = testCasesObject.reduce(function (previousArr, currElement, currIndex) {
if (previousArr.length === 0) {
let obj = {testSetName: currElement.testSetName, testCases: []};
obj.testCases.push(currElement.data.body.key);
previousArr.push(obj);
}
else {
let isAdded = false;
for (let index = 0; index < previousArr.length; index += 1) {
if (previousArr[index].testSetName === currElement.testSetName) {
previousArr[index].testCases.push(currElement.data.body.key);
isAdded = true;
}
}
if (!isAdded) {
let obj = {testSetName: currElement.testSetName, testCases: []};
obj.testCases.push(currElement.data.body.key);
previousArr.push(obj);
}
}
return previousArr;
}, []);
console.log(results);
My code generates accurate results but I want to make it more efficient and I need help on this.

You could group by testSetName and reduce the array with a lookup for an already inserted item.
var array = [{ failureMessage: "failed", data: { statusCode: 201, body: { id: "14975", key: "KEY-4855" } }, testSetName: "search" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4856" } }, testSetName: "download" }, { failureMessage: "failed 2", data: { statusCode: 201, body: { id: "14975", key: "KEY-4857" } }, testSetName: "search" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4858" } }, testSetName: "download" }, { failureMessage: "failed", data: { statusCode: 201, body: { id: "14975", key: "KEY-4859" } }, testSetName: "backgrounds" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4860" } }, testSetName: "backgrounds" }],
result = array.reduce((r, { testSetName, data: { body: { key } } }) => {
var item = r.find(o => o.testSetName === testSetName);
if (item) {
item.testCases.push(key);
} else {
r.push({ testSetName, testCases: [key] });
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

What you want to achieve contains an algorithm often called "group by". There is a lodash implementation you can use: _.groupBy
This will give you an object indexed by "testSetName". Then you can go forward and map this to your desired structure.
const indexedByTestSetName = _.groupBy(data, item => item.testSetName)
// {search: [{testSetName: 'search', failureMessage: 'failed', data: {}}, ...]
const tests = Object.keys(indexedByTestSetName).map(key => ({
testSetName: key,
testCases: indexedByTestSetName[key]
)})
// [{testSetName: 'search', testCases: [{testSetName: 'search', failureMessage: 'failed', data: {}}, ...]}]
This is more efficient in terms of "lines of code", but how the performance compares is hard to guess. If you don't face millions of entries, I would not bother.

Related

Mongoose, updated nested array

My question is:
How can I query in the nested arrays?
I want to change value in key "likeUp" which is nested inside object in array "usersWhoLiked". Where "usersWhoLiked" is nested in array "comments"
How Can I do that with mongoose ?
Request that I wrote beneath... do not work, but is very similar to answer given in StackOverflow post: Mongoose update update nested object inside an array
This is my request to db with updateOne:
try {
const response = await Comments.updateOne(
{
productId,
comments: { $elemMatch: { usersWhoLiked: { $elemMatch: { userId } } } },
},
{
$set: { 'comments.$[outer].usersWhoLiked.$[inner].likeUp': likes.up },
},
{
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
}
).exec();
return res.status(201).json({ response });
} catch (err) {
console.log(err);
return res.send(err);
}
This is the collection, that I am trying to update:
{
"_id": {
"$oid": "6307569d2308b78b378cc802"
},
"productId": "629da4b6634d5d11a859d729",
"comments": [
{
"userId": "62f29c2c324f4778dff443f6",
"userName": "User",
"date": "2022.08.25",
"confirmed": true,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 5,
"description": "Nowy komentarz"
},
"_id": {
"$oid": "630756b22308b78b378cc809"
},
"usersWhoLiked": [
{
"userId": "62f29c2c324f4778dff443f1",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80e"
}
},
{
"userId": "62f29c2c324f4778dff443f2",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80c"
}
}
]
}
],
"__v": 0
}
Mongooes schema for comment collection:
const commentSchema = new Schema({
productId: String,
comments: [
{
userId: String,
userName: String,
date: String,
confirmed: Boolean,
likes: {
up: {
type: Number,
default: 0,
},
down: {
type: Number,
default: 0,
},
},
content: {
rating: Number,
description: String,
},
usersWhoLiked: [{ userId: String, likeUp: Boolean }],
},
],
});
I guess the problem is with your arrayFilters operator, because you are trying to filter by field _userId which does not exist:
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
I managed to update the likeUp value using the following query:
db.collection.update({
_id: ObjectId("6307569d2308b78b378cc802")
},
{
$set: {
"comments.$[user].usersWhoLiked.$[like].likeUp": false
}
},
{
arrayFilters: [
{
"user._id": ObjectId("630756b22308b78b378cc809")
},
{
"like.userId": "62f29c2c324f4778dff443f1"
}
]
})
Try it on MongoDB playground: https://mongoplayground.net/p/XhQMNBgEdhp

MongooseJS: How to remove 1 object inside Array in Array of Objects

Hi MongooseJS experts!
I'm new in MongooseJS, This is my 2nd day of solving this problem but I can't find a working solution to this.
Thank you in advance!
My Delete method
Cart.updateOne(
{ "content.merchantId": req.body.merchantId },
{ $pull: { "content.items._id": req.body.productId } },
{ new: true },
function (error, result) {
if (error) { }
else if (result) { }
}
);
Schema
const CartSchema = new Schema({
customerId: {
type: String,
required: true,
},
content: {
merchantName: {
type: String,
required: true,
},
merchantId: {
type: String,
required: true,
},
items: [],
},
});
Sample JSON
[
{
"content": {
"merchantName": "SAMPLE_MERCHANT_NAME",
"merchantId": "SAMPLE_MERCHANT_ID",
"items": [
{
"_id": "SAMPLE_ID",
"title": "SAMPLE TITLE",
}
]
},
"_id": "618220e83966345ab5d451cd",
"__v": 0
},
]
Error message
Cannot use the part (_id) of (content.items._id) to traverse the element ({items: [{ _id: "SAMPLE_ID", title: "SAMPLE TITLE"}] })
you should use like this
db.collection.update({
"content.merchantId": "SAMPLE_MERCHANT_ID"
},
{
$pull: {
"content.items": {
"_id": "SAMPLE_ID"
}
}
},
{
new:true
},
)
https://mongoplayground.net/p/Ou26tab2mBU

Filter nested of nested in Mongoose Populate

I have an object that looks like this: (that is the output of Mongoose query)
let systems = [
{
"maxUserLevel": 1,
"subsystems": [
{
"sections": [],
"name": "apple"
},
{
"sections": [
{
"name": "banana"
}
],
"name": "sun",
},
{
"sections": [],
"name": "orange"
}
],
"systemID": "12345"
},
{
"maxUserLevel": 3,
"subsystems": [
{
"sections": [],
"name": "blue"
},
{
"sections": [
{
"name": "pink"
}
],
"name": "red",
},
],
"systemID": "15654"
}];
The Mongoose query:
this.model.System.find({username: user.username}, {
_id: 0,
allowedOrganizations: 0,
name: 0,
updatedAt: 0,
createdAt: 0,
versionKey: 0
})
.populate(
{
path: "subsystems",
populate: {
path: "sections",
select: "name -_id",
match: {
allowedUsers: user.id
}
},
select: "name metadata -_id",
}
)
.exec((error, systems) => {
return res.status(200).json({
data: systems,
success: true
});
});
I'm looking for a way to removes the subsystems that do not have sections.
After hours of searching I think there's no way to filter populate based on nested populate, so I tried with some ways like this:
if (systems.subsystems.length > 0) {
let test = [];
systems.subsystems.forEach((value, index) => {
if (value.sections.length !== 0) {
test[index] = value;
}
if (systems.subsystems.length === index + 1) {
return test;
}
})
}
But I'm not sure if this is the correct way.
You can use an aggregate query with $filter like this:
db.collection.aggregate([
{
"$project": {
"_id": 1,
"maxUserLevel": 1,
"subsystems": {
"$filter": {
"input": "$subsystems",
"as": "s",
"cond": {
"$ne": [
"$$s.sections",
[]
]
}
}
}
}
}
])
Example here
Also your query should contains a $match stage (like your find stage) and $lookup.
I'm not sure this is the best way, but it solved my problem:
const _ = require('lodash');
systems.forEach((value, index) => {
systems[index].subsystems = _.filter(value.subsystems,
item => !item.sections.length == 0
);
if (systems.length === index + 1) {
return systems;
}
});
It removes all subsystems that do not have sections.

Javascript Object array get last array

I have a json object array I have two functions. One to get the last message and the other to get. I need to keep the outer format the same but only return the one message.
I am getting the Json from the Telegram api and I have a Node Express script to return the reformatted Json
Here is the full Json:
{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I have a function to store the object after an api call to Telegram:
storeUpdates(data){
this.messageData = data;
}
For the function to get the last message:
getlastMessage() {
return
}
I am trying to return the Json:
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
And for the function to get a specific update_id
getNextMessage(update_id) {
return
}
Again I am trying to get this format of a single message matching the passed in update_id
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I am a little confused with the layers of object and arrays mixed.
Does this work?
const messages = {
ok: true,
result: [{
update_id: 650787950,
channel_post: {
message_id: 258,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256395,
text: 'test messge',
},
},
{
update_id: 650787951,
channel_post: {
message_id: 259,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256604,
text: 'next',
},
},
],
};
const getLastMessage = (messages) => {
final = {
ok: true,
result: [],
};
final.result.push(messages.result[messages.result.length - 1]);
return final;
};
const getNextMessage = (update_id, messages) => {
final = {
ok: true
};
final.result = messages.result.filter((msg) => {
return msg.update_id === update_id;
});
return final;
};
console.log(getLastMessage(messages));
console.log(getNextMessage(650787950, messages));
You get the last message by returning the last element in the array, by getting the length of the array and -1
I used Array.prototype.filter() to find the correct object.
To get the last result you would need to go to results and return the last index:
function getlastMessage(resultObject) {
return {
ok: resultObject.ok
result: [resultObject.result[resultObject.result.length - 1]]
}
}
To get the message by update_id:
getNextMessage(update_id) {
return {
ok: resultObject.ok
result: [resultObject.result.find(message => message.update_id === update_id)]
}
}
Something along these lines
Using destructuring you can make your code a little bit more compact:
const someObject = JSON.parse(`{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}`)
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.find(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: someObject.result[arrayLength - 1]
}
}
console.log(getNextMessage(650787950))
console.log(getLastMessage())
If you want to keep the result type as an array you can use filter instead of find and surround the last element of result array with square brackets, like this:
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.filter(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: [someObject.result[arrayLength - 1]]
}
}

Parse array of objects recursively and filter object based on id

i have this array of objects : getCategory (variable)
[
{
"id": "20584",
"name": "Produits de coiffure",
"subCategory": [
{
"id": "20590",
"name": "Coloration cheveux",
"subCategory": [
{
"id": "20591",
"name": "Avec ammoniaque"
},
{
"id": "20595",
"name": "Sans ammoniaque"
},
{
"id": "20596",
"name": "Soin cheveux colorés"
},
{
"id": "20597",
"name": "Protection"
},
{
"id": "20598",
"name": "Nuancier de couleurs"
}
]
},
{
"id": "20593",
"name": "Soins cheveux",
"subCategory": [
{
"id": "20594",
"name": "Shampooing"
},
{
"id": "20599",
"name": "Après-shampooing"
},
{
"id": "20600",
"name": "Masques"
},
and i tried everything i could search in stackoverflow ..
lets say on this array i want to get recursively and object with the specified id .. like 20596 and it should return
{
"id": "20596",
"name": "Soin cheveux colorés"
}
The logic way i am doing is like this :
var getSubcategory = getCategory.filter(function f(obj){
if ('subCategory' in obj) {
return obj.id == '20596' || obj.subCategory.filter(f);
}
else {
return obj.id == '20596';
}
});
dont know what else to do .
Thanks
PS : I dont use it in browser so i cannot use any library . Just serverside with no other library . find dont work so i can only use filter
You need to return the found object.
function find(array, id) {
var result;
array.some(function (object) {
if (object.id === id) {
return result = object;
}
if (object.subCategory) {
return result = find(object.subCategory, id);
}
});
return result;
}
var data = [{ id: "20584", name: "Produits de coiffure", subCategory: [{ id: "20590", name: "Coloration cheveux", subCategory: [{ id: "20591", name: "Avec ammoniaque" }, { id: "20595", name: "Sans ammoniaque" }, { id: "20596", name: "Soin cheveux colorés" }, { id: "20597", name: "Protection" }, { id: "20598", name: "Nuancier de couleurs" }] }, { id: "20593", name: "Soins cheveux", subCategory: [{ id: "20594", name: "Shampooing" }, { id: "20599", name: "Après-shampooing" }, { id: "20600", name: "Masques" }] }] }];
console.log(find(data, '20596'));
console.log(find(data, ''));

Categories

Resources