Combining two objects into one object and sorting by timestamp - javascript

In Laravel, I have used this approach to combine to collections together and returning as one collection.
$collection = $messages->merge($texts)->sortByDesc('created_at')
If I dd($colection), it shows Collection object all combined and sorted together.
Then I tried to send it to vue via ajax, however, the data is separated again. So my object looks like this:
item: {
messages: [
0: { ... }
1: { ... }
2: { ... }
3: { ... }
],
texts: [
0: { ... }
1: { ... }
]
}
this is because return response()->json('item' => '$collection') separates them as messages and texts again.
I tried combining them like this, but it overwritten the values (I assume because ids are same).
vm item = this;
// in response of ajax get,
.then(function(response) {
var item = response.data.item;
Object.assign(vm.item.messages, vm.item.texts);
});
What is the right way to combine texts into messages and sorting them by timestamps? They all have created_at in the first level of objects like this:
messages: [
0: { created_at: ... }
],
texts: [
0: { created_at: ... }
]
Update: After icepickle's answer, with concat, I was able to combine them in messages array. Now, I have an issue for created_at values as they are converted to strings. Here are some test data. This is what I got after ordering:
messages: [
0: {
msg: 'hello',
created_at: "2017-10-12 00:48:59"
},
1: {
msg: 'mellow',
created_at: "2017-10-11 16:05:01"
},
2: {
msg: 'meow',
created_at: "2017-10-11 15:07:06"
},
4: {
msg: 'test'
created_at: "2017-10-11 17:13:24"
}
5: {
msg: 'latest'
created_at: "2017-10-12 00:49:17"
}
],

Wouldn't it be enough to concat the arrays, and then sort?
A bit like
let result = ([]).concat(item.messages, item.texts);
or in es6
let result = [...item.messages, ...item.texts]
and then calling sort on the result
// in place sort, result will be sorted, and return the sorted array
result.sort((a, b) => a.created_at - b.created_at);
const items = {
messages: [
{
msg: 'hello',
created_at: "2017-10-12 00:48:59"
},
{
msg: 'mellow',
created_at: "2017-10-11 16:05:01"
},
{
msg: 'meow',
created_at: "2017-10-11 15:07:06"
}
],
texts: [
{
msg: 'test',
created_at: "2017-10-11 17:13:24"
},
{
msg: 'latest',
created_at: "2017-10-12 00:49:17"
}
]
};
let result = [...items.messages, ...items.texts].sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
console.log( result );

Related

Javascript extracting values from deeply nested array object structure

I'm trying to pull out specific fields from backend data to prep the body of a table. The data coming in has the structure of:
[
{
_id: "63056cee252b83f4bc8f97e9",
goals: [
{ title: "Cook" },
{ title: "Budget" }
],
visitEnd: "2022-08-18T00:30:00.000Z",
visitStart: "2022-08-17T21:30:00.000Z",
},
{
_id: "63223586798c6b2658a0d576",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Clean" }
],
visitEnd: "2022-09-13T00:30:00.000Z",
visitStart: "2022-09-12T22:00:00.000Z"
},
{
_id: "63542ecfca5bd097a0d9acaf",
goals: [
{ title: "Cook" },
{ title: "Clean" }
],
visitEnd: "2022-10-12T19:00:11.000Z",
visitStart: "2022-10-12T17:00:00.000Z",
}]
Since the table headers are by month/year, I'm using lodash to group them by month, which gets me here:
Object { 7: (2) […], 8: (2) […], 9: (2) […] }
​
7: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Firm Office in LA", visitStart: "2022-08-17T21:30:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-08-11T21:00:57.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
8: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-09-12T22:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-09-21T21:00:00.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
9: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-10-12T17:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-10-21T21:00:00.000Z", … }
​​
length: 2
But now I'm stuck since I want to isolate the fields of the goals array, which is within the objects, within the array of each month, which is contained in an object. I've tried playing around with Object.keys and maps, and then from here: https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4 came across a function to get deeply nested items. But I'm still messing this up, and my head is spinning trying to make sense of it. I looked at lodash's map and property, but was not sure how to implement given the layers of nesting I'm trying to work through on dynamically named arrays within the groupBy object. Heres where I'm at, but I'm getting the error i.map is not a function
const sort = groupBy(visits, ({visitEnd})=> new Date(visitEnd).getMonth());
console.log("sort 1: ", sort)
const stage = Object.keys(sort).map((i) => {
{ i.map((el) => getNestedObject(el, ['goals', 'title'])) }
})
console.log("sort 2: ", stage)
My javascript knowledge is terrible which doesn't help...
The error you're getting, i.map is not a function, means that the variable i is not an array. Based on the data you supplied in your post i is an object.
Iterate the result of the sorted month/year data using Object.entries() versus Object.keys().
To get a list of unique goals per month with output that looks like:
{
7: ["Cook", "Spend", "Clean"],
8: ["Cook", "Budget", "Clean"],
9: ["Cook", "Budget", "Scrub", "Fold", "Rest", "Wash"]
}
const dataSortedByMoYrObj = {
7: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Firm Office in LA", visitStart: "2022-08-17T21:30:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Spend" },
{ title: "Clean" }
]
},
{
user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-08-11T21:00:57.000Z",
goals: [
{ title: "Cook" },
{ title: "Clean" }
]
}
],
8: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-09-12T22:00:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Clean" }
]
},
{ user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-09-21T21:00:00.000Z" }
],
9: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-10-12T17:00:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Scrub" }
]
},
{
user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-10-21T21:00:00.000Z",
goals: [
{ title: "Fold" },
{ title: "Rest" },
{ title: "Wash" }
]
}
]
};
// 'const getNestedObject' code sourced from:
// https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4
const getNestedObject = (nestedObj, pathArr) => {
return pathArr.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}
const goalsByMonthYearObj = {};
Object.entries(dataSortedByMoYrObj).forEach(([month, users]) => {
// 'month' represents the key.
// 'users' is an array of objects listed for each month.
let goalsByMonth = [];
users.map(user => {
const goalsProp = getNestedObject(user, ['goals']);
// Check if the 'goals' property is a valid.
// If 'goals' property is 'null' or 'undefined',
// '!Array.isArray(null)' returns 'true'.
if (!Array.isArray(goalsProp)) { return; }
// Convert list of goal objects (e.g. '{title: Budget}')
// to an array using 'goalsProp.map()' and then
// concatenate goals array to the existing
// goals-by-month array.
goalsByMonth = goalsByMonth.concat(goalsProp.map(goal => goal.title));
});
// Add array of unique goals for each month
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
goalsByMonthYearObj[month] = [...new Set(goalsByMonth)];
});
console.log(goalsByMonthYearObj);
(Original code that's not as concise as above snippet.)
const goalsByMonthYearObj = {};
// Reference to 'Object.entries()' at:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
for (const [key, value] of Object.entries(dataSortedByMoYrObj)) {
// 'key' represents a month index.
// 'value' contains an array of objects listed for each month index.
//console.log(`${key}: ${value}`);
const goalsByMonth = [];
value.forEach(item => {
// The 'goals' property is only one level deep so
// it's not necessary to use the 'getNestedObject()'
// function.
// For example: const goalsProp = item.goals;
// The function is useful for more deeply
// embedded properties.
const goalsProp = getNestedObject(item, ['goals']);
if (!Array.isArray(goalsProp)) { return; }
goalsProp.forEach(goal => {
if (!goal.title) { return; }
goalsByMonth.push(goal.title);
});
});
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
const uniqueGoals = [...new Set(goalsByMonth)];
goalsByMonthYearObj[key] = uniqueGoals;
}
console.log(goalsByMonthYearObj);

Edit multiple objects in array using mongoose (MongoDB)

So I tried several ways, but I can't, I can modify several objects with the same key but I can't modify any with different keys, if anyone can help me is quite a complex problem
{
id: 123,
"infos": [
{ name: 'Joe', value: 'Disabled', id: 0 },
{ name: 'Adam', value: 'Enabled', id: 0 }
]
};
In my database I have a collection with an array and several objects inside which gives this.
I want to modify these objects, filter by their name and modify the value.
To give you a better example, my site returns me an object with the new data, and I want to modify the database object with the new object, without clearing the array, the name key never changes.
const object = [
{ name: 'Joe', value: 'Hey', id: 1 },
{ name: 'Adam', value: 'None', id: 1 }
];
for(const obj in object) {
Schema.findOneAndUpdate({ id: 123 }, {
$set: {
[`infos.${obj}.value`]: "Test"
}
})
}
This code works but it is not optimized, it makes several requests, I would like to do everything in one request, and also it doesn't update the id, only the value.
If anyone can help me that would be great, I've looked everywhere and can't find anything
My schema structure
new Schema({
id: { "type": String, "required": true, "unique": true },
infos: []
})
I use the $addToSet method to insert objects into the infos array
Try This :
db.collection.update({
id: 123,
},
{
$set: {
"infos.$[x].value": "Value",
"infos.$[x].name": "User"
}
},
{
arrayFilters: [
{
"x.id": {
$in: [
1
]
}
},
],
multi: true
})
The all positional $[] operator acts as a placeholder for all elements in the array field.
In $in you can use dynamic array of id.
Ex :
const ids = [1,2,..n]
db.collection.update(
//Same code as it is...
{
arrayFilters: [
{
"x.id": {
$in: ids
}
},
],
multi: true
})
MongoPlayGround Link : https://mongoplayground.net/p/Tuz831lkPqk
Maybe you look for something like this:
db.collection.update({},
{
$set: {
"infos.$[x].value": "test1",
"infos.$[x].id": 10,
"infos.$[y].value": "test2",
"infos.$[y].id": 20
}
},
{
arrayFilters: [
{
"x.name": "Adam"
},
{
"y.name": "Joe"
}
],
multi: true
})
Explained:
You define arrayFilters for all names in objects you have and update the values & id in all documents ...
playground

Getting undefined result when trying to loop and filtering array

I am currently working with objects and arrays in nodejs in conjuction with filters. I am currenlty facing difficulty in figuring out how to properly traverse an object and filter for the desired results. Instead I am getting undefined. I have an object users and I am wanting to filter for each user configuration that has active === true and then ultimately display every users configuration with that filter in the final result. What is the right/best way to approach this? Should I use map?
Current Result:
undefined
Desired Result:
[
{
email: 'test1#email.com',
active: true
},
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
]
Code:
const users = [
{
name: 'User1',
configuration: [
{
email: 'test1#email.com',
active: true
},
{
email: 'test2#email.com',
active: false
}
],
},
{
name: 'User2',
configuration: [
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
],
},
];
const result = users.forEach(user => user.configuration.filter( x => {
let {
active
} = x;
return active === true;
}));
console.log(result);
you can use flatMap for this. forEach always returns undefined. usually if you want to return some array use map but since filter also returns an array you need to flat it to get your desired result hence flatMap
const users = [{name: 'User1',configuration: [ {email: 'test1#email.com',active: true},{email: 'test2#email.com',active: false}],},{name: 'User2',configuration: [ {email: 'test3#email.com',active: true},{email: 'test4#email.com',active: true}],},];
const result = users.flatMap(user => user.configuration.filter( x => x.active===true));
console.log(result);

Map the nested data from other table using promise and async-await

I need the expert advice for this code. I need to know Is there any better way to solve this.
I am using the mongoose for db. I have a dataset like this:
Below is matchTable:
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
}
],
status: true
}
And I have a Car table in which car name is there on behalf of id
like this
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febce'), name: 'ford' },
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febcg'), name: 'mitsubishi' },
So I want to make join the data from car table, so that response get name on behalf of aid.
Desired result will be like
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
name: 'mitsubishi'
}
],
status: true
}
For that I have to merge the car table on matchTable. I have done this but I want to give some suggestion that is there any better way to do or is it fine. I need expert advice.
const getData = await matchTable.find(
{ status: true }
).lean().exec();
let dataHolder = [];
await Promise.all (
getData.map(async x => {
await Promise.all(
x.car.map(async y => {
let data = await Car.findOne(
{ _id: ObjectId(y.aid) },
{ name: 1 }
).lean().exec();
y.name = '';
if (data) {
y.name = data.name;
}
})
)
// If I return { ...x }, then on response it will return {}, {} on car column
dataHolder.push(x) //So I have chosen this approach
})
);
Please guide me if any better and efficient solution is there. Thanks in advance
You can make use of aggregation here.
const pipeline = [
{
$match : { status : true }
},
{
$unwind: '$matchtable',
},
{
$lookup: {
from: "cars",
localField: "car.aid",
foreignField: "_id",
as: "matchcars"
}
},
{
$addFields: {
"car.carName": { $arrayElemAt: ["$matchcars.name", 0] }
}
},
{
$group: {
_id: "$_id",
cars: { $push: "$matchcars" }
}
}
]
const result = await matchTable.aggregate(pipeline).exec();
Please make sure, aid field inside car array (in matchTable collection) is an ObjectId because its being matched to _id (which is an ObjectId) inside cars collection.

Filter array of objects to a single matching object in mongodb/meteor

I have a query which looks as so:
var writer = Writers.findOne({
_id: writerId,
books: {
$elemMatch: {
id: Books.findOne({ slug: bookSlug })._id
}
}
});
However, this will return the full list of classes in the query.
{
name: "H.P. Lovecraft",
books: [{
id: "1234",
slug: "at-the-mountains-of-madness"
}, {
id: "5678",
slug: "herbert-west-reanimator"
}]
}
Would there be a way to eliminate all information except for the one item in the list I want and make it into an object? That is to say, I want my final result to be:
{
name: "H.P Lovecraft",
book: {
id: "1234",
slug: "herbert-west-reanimator"
}
}
How would this be done in Meteor with mongodb?
One approach you could take is to use the $elemMatch projection operator with the findOne() query. For the document with _id equal to writerId, the $elemMatch projection returns only the first matching element from the array:
var bookId = Books.findOne({ slug: bookSlug })._id,
writer = Writers.findOne({ _id: writerId },
{ books: { $elemMatch: { id: bookId } },
_id: 0,
name: 1
}
);
Another approach would be to use Underscore library's _.find() method to return the specific array element:
var bookId = Books.findOne({ slug: bookSlug })._id,
writer = Writers.findOne({
_id: writerId,
books: {
$elemMatch: {
id: bookId
}
}
}),
book = _.find(writer.books, function(book) {return book.id === bookId});

Categories

Resources