Using Jest property matchers on arrays of objects - javascript

I am attempting to use Jest's new Property Matcher feature (since Jest 23.0.0) to match on an array of objects that contain a generated field. I have tried putting both a plain object and a matcher definition using expect.arrayContaining and expect.objectContaining like I might when matching manually. Is there any way to do this currently?
const sportsBallPeople = [
{
createdAt: new Date(),
name: 'That one famous guy from Cleveland'
},
{
createdAt: new Date(),
name: 'That tall guy'
}
];
expect(sportsBallPeople).toMatchSnapshot(<something goes here>);

Version Info
As is noted in the question, property matchers were introduced in Jest 23.0.0. Note that apps bootstrapped with create-react-app as of today (Aug 5, 2018) are still < 23.
OBJECT
Here is an example using a property matcher for a single object:
test('sportsBallPerson', () => {
expect(sportsBallPeople[0]).toMatchSnapshot({
createdAt: expect.any(Date)
})
});
The snapshot generated:
exports[`sportsBallPerson 1`] = `
Object {
"createdAt": Any<Date>,
"name": "That one famous guy from Cleveland",
}
`;
This will correctly match createdAt to any date and the name to exactly "That one famous guy from Cleveland".
ARRAY
To test an array of objects using property matchers use forEach to loop over the array and snapshot test each object individually:
test('sportsBallPeople', () => {
sportsBallPeople.forEach((sportsBallPerson) => {
expect(sportsBallPerson).toMatchSnapshot({
createdAt: expect.any(Date)
});
});
});
The snapshots generated:
exports[`sportsBallPeople 1`] = `
Object {
"createdAt": Any<Date>,
"name": "That one famous guy from Cleveland",
}
`;
exports[`sportsBallPeople 2`] = `
Object {
"createdAt": Any<Date>,
"name": "That tall guy",
}
`;
forEach ensures that the objects are tested in order, and each object is properly snapshot tested as described above.
Additional Info
It is interesting to note that directly testing an array using property matchers does not work properly and has unexpected side-effects.
My first attempt to test an array was to create the following test:
test('sportsBallPeople as array', () => {
expect(sportsBallPeople).toMatchSnapshot([
{ createdAt: expect.any(Date) },
{ createdAt: expect.any(Date) }
]);
});
It generated the following snapshot:
exports[`sportsBallPeople as array 1`] = `
Array [
Object {
"createdAt": Any<Date>,
},
Object {
"createdAt": Any<Date>,
},
]
`;
This is incorrect since the name properties are missing, but the test still passes (Jest v23.4.2). The test passes even if the names are changed and additional properties are added.
Even more interesting was that as soon as this test executed, any following tests using property matchers were adversely affected. For example, placing this test ahead of the the test looping over the objects changed those snapshots to the following:
exports[`sportsBallPeople 1`] = `
Object {
"createdAt": Any<Date>,
}
`;
exports[`sportsBallPeople 2`] = `
Object {
"createdAt": Any<Date>,
}
`;
In summary, directly passing an array to use with property matchers does not work and can negatively affect other snapshot tests using property matchers.

toMatchObject works for an array too because arrays are objects
expect(receivedArray).toMatchObject(expectedArray)

To apply snapshot property matcher to each array entry without creating a separate assertion for each, we may create an array with length equal to the value's length filled with the matcher definition:
it('should return first 10 notes by default', async () => {
const noteMatcher = {
createdAt: expect.any(String),
updatedAt: expect.any(String),
}
const response = await app.inject({
method: 'GET',
url: `/examples/users/1/notes`,
})
const payload = response.json()
const { length } = payload.data
expect(response.statusCode).toMatchInlineSnapshot(`200`)
expect(length).toBe(10)
expect(payload).toMatchSnapshot({
data: new Array(length).fill(noteMatcher),
})
})
Will result in the following snapshot:
exports[`should return first 10 notes by default 2`] = `
Object {
"data": Array [
Object {
"createdAt": Any<String>,
"deletedAt": null,
"id": 1,
"note": "Note 1",
"title": "Title 1",
"updatedAt": Any<String>,
"userID": 1,
},
Object {
"createdAt": Any<String>,
"deletedAt": null,
"id": 2,
"note": "Note 2",
"title": "Title 2",
"updatedAt": Any<String>,
"userID": 1,
},
// 8 omitted entries
],
"success": true,
}
`;

Create an array of Property Matcher (using Array(n).fill(matcher) for example), of the same size as the result object you want to match (n=sportsBallPeople.length). matcher representing here the Property Matcher of one item of your array.
That way:
It will check each element of the array with the property matcher.
It will create only one snapshot with the full array.
If the result is not the same size as the last snapshot, the test will fail because the snapshot will be different. So it will fail even if the new result is bigger
(others answers may not fail when the array grow if they create one snapshot per item, as new snapshot are usually silently created in CI and doesn't trigger a test failure)
const sportsBallPeople = [
{
createdAt: new Date(),
name: 'That one famous guy from Cleveland'
},
{
createdAt: new Date(),
name: 'That tall guy'
}
];
const itemMatcher = {
createdAt: expect.any(Date),
}
const arrayMatcher = Array(sportsBallPeople.length).fill(itemMatcher)
expect(sportsBallPeople).toMatchSnapshot(arrayMatcher);
or, simply:
expect(sportsBallPeople).toMatchSnapshot(Array(sportsBallPeople.length).fill({
createdAt: expect.any(Date),
}));
Resulting snapshot will be:
exports[`snapshot 1`] = `
Array [
Object {
"createdAt": Any<Date>,
"name": "That one famous guy from Cleveland",
},
Object {
"createdAt": Any<Date>,
"name": "That tall guy",
},
]`

Thanks for the tips.
Often, being a test you can control the inputs making something like the following viable.
describe.only('Something', () => {
it.only('should do something', () => {
const x = {
a: false,
b: true,
c: 157286400,
};
const results = functionBeingTesting(x, 84);
expect(results[0]).toMatchInlineSnapshot({
createdAt: expect.any(Number),
updatedAt: expect.any(Number)
},
`
Object {
"createdAt": Any<Number>,
"a": false,
"b": true,
"updatedAt": Any<Number>,
"value": "0",
}
`,
);
expect(results[1]).toMatchInlineSnapshot({
createdAt: expect.any(Number),
updatedAt: expect.any(Number)
},
`
Object {
"createdAt": Any<Number>,
"a": false,
"b": true,
"updatedAt": Any<Number>,
"value": "1",
}
`,
);
expect(results[2]).toMatchInlineSnapshot({
createdAt: expect.any(Number),
updatedAt: expect.any(Number)
},
`
Object {
"createdAt": Any<Number>,
"a": false,
"b": true,
"updatedAt": Any<Number>,
"value": "1",
}
`,
);
});
});

Related

JS map array to return object of arrays for React

If I want to return an array of objects from a nested array in JS/React, what would be the way to do this? I have tried the following, but this gives an error about react children - objects cant be rendered as children try an array.
data:
{
"title": 0,
"name": 0,
"score": 0,
"summary": [
{
"id": 1,
"start": "2019-11-01",
"end": "2019-11-04"
},
{
"id": 2,
"start": "2019-11-01",
"end": "2019-11-04"
}
]
}
I have tried:
const newArray = result?.summary?.map((inner: any) => {
return (
{
from: new Date(inner?.start),
to: new Date(inner?.end),
label: {
text: (inner?.id),
},
}
)
})
I want to create a new array of objects with the data from the summary nested array?
any idea's?
This is the issue. You need to convert your dates to strings. The third-party package you input this array tries to render the Date objects and fails to do so. The date is object type and that is what the error is all about.
Try this:
const newArray = result?.summary?.map((inner: any) => {
return (
{
from: new Date(inner?.start).toString(),
to: new Date(inner?.end).toString(),
label: {
text: (inner?.id),
},
}
)
})
Use toDateString to get a formatted date string.

Update element in array of objects that have certain criteria

I have a an array of chat rooms, each room has a messages array property.
// state
const INITIAL_STATE = {
myRooms: {
rooms: [],
isLoading: false,
isLoaded: false,
isError: false,
},
};
A room and its elements is defined as
{
"creator": {
"username": "LangCodex"
},
"joiner": {
"username": "Bingo"
},
"date_created": "2020-10-04T19:23:01.380918",
"messages": [],
"name": "9496dd0a223f712f4a9d2f3fba4a0ab0",
"status": "offline"
}
A message and its elements is defined as below:
{
"author": {
"username": "Bingo"
},
"recipient": {
"username": "LangCodex"
},
"body": "hello",
"date": "2020-10-07T11:11:25.828269",
"id": 602,
"room": "9496dd0a223f712f4a9d2f3fba4a0ab0",
"seen": false,
"type": "text"
},
My reducer is defined as below and it's receiving data of type String (roomName) by which I select the room whose messages's seen properties are to be set to true.
case 'MARK_CHAT_AS_READ': {
const roomIndex = state.myRooms.rooms.findIndex(r => r.name === action.payload.roomName);
// magic happens here
return {...state}
}
I have been struggling with this one for quite a while now. Any help would be much appreciated.
Edit:
What I am trying to do is to set the 'seen' property of every message of the room (whose index is returned by roomIndex) to true.
Something like this should do the trick
case 'MARK_CHAT_AS_READ': {
return {
...state, // copy state
myRooms: {
...state.myRooms, // copy myRooms
rooms: state.myRooms.rooms.map(room => { // create new rooms array
// keep room untouched if the name is different
if (room.name !== action.payload.roomName) return room;
return { // create new room
...room,
// with new messages array, containing updated values
messages: room.messages.map(message => ({...message, seen: true}))
};
}),
}
}
}
BUT. You should better normalize redux structure and use immer to avoid nested updates.

Filter out objects in array if one value is the same

I am fetching data from an api that, sometimes, gives me multiple objects with the same values, or very similar values, which I want to remove.
For example, I might get back:
[
{
"Name": "blah",
"Date": "1992-02-18T00:00:00.000Z",
"Language": "English",
},
{
"Name": "blahzay",
"Date": "1998-02-18T00:00:00.000Z",
"Language": "French",
}, {
"Name": "blah", // same name, no problem
"Date": "1999-02-18T00:00:00.000Z", // different date
"Language": "English", // but same language
},
]
So I want to check that no two objects have a key with the same "Language" value (in this case, "English").
I would like to get the general process of filtering out the entire object if it's "Language" value is duplicated, with the extra issue of not having the same number of objects returned each time. So, allowing for dynamic number of objects in the array.
There is an example here:
Unexpeected result when filtering one object array against two other object arrays
but it's assuming that you have a set number of objects in the array and you are only comparing the contents of those same objects each time.
I would be looking for a way to compare
arrayName[eachObject].Language === "English"
and keep one of the objects but any others (an unknown number of objects) should be filtered out, most probably using .filter() method along with .map().
The below snippets stores the languages that have been encountered in an array. If the current objects language is in the array then it is filtered out. It makes the assumption that the first object encountered with the language is stored.
const objs = [
{
"Name": "blah",
"Date": "1992-02-18T00:00:00.000Z",
"Language": "English",
},
{
"Name": "blahzay",
"Date": "1998-02-18T00:00:00.000Z",
"Language": "French",
}, {
"Name": "blah", // same name, no problem
"Date": "1999-02-18T00:00:00.000Z", // different date
"Language": "English", // but same language
},
],
presentLanguages = [];
let languageIsNotPresent;
const objsFilteredByLanguage = objs.filter(function (o) {
languageIsNotPresent = presentLanguages.indexOf(o.Language) == -1;
presentLanguages.push(o.Language);
return languageIsNotPresent;
});
console.log(objsFilteredByLanguage);
You could take a hash table and filter the array by checking Name and Language.
var array = [{ Name: "blah", Date: "1992-02-18T00:00:00.000Z", Language: "English" }, { Name: "blahzay", Date: "1998-02-18T00:00:00.000Z", Language: "French" }, { Name: "blah", Date: "1999-02-18T00:00:00.000Z", Language: "English" }],
hash = {},
result = array.filter(({ Name, Language }) => {
var key = `${Name}|${Language}`;
if (!hash[key]) return hash[key] = true;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using Set makes it easy to remove duplicates for as many keys as you like. I tried to be as verbose as possible so that each step was clear.
var objects = [{ "Name": "blah", "Date": "1992-02-18T00:00:00.000Z", "Language": "English", }, { "Name": "blah", "Date": "1998-02-18T00:00:00.000Z", "Language": "French", }, { "Name": "blah", "Date": "1999-02-18T00:00:00.000Z", "Language": "English" }];
function uniqueKeyVals(objects, key) {
const objVals = objects.map(object => object[key]); // ex. ["English", "French", "English"]
return objects.slice(0, new Set(objVals).size); // ex. { "English", "French" }.size = 2
}
function removeKeyDuplicates(objects, keys) {
keys.forEach(key => objects = uniqueKeyVals(objects, key));
return objects;
}
// can also use uniqueKeyVals(key) directly for just one key
console.log("Unique 'Language': \n", removeKeyDuplicates(objects, ["Language"]));
console.log("Unique ['Language', 'Name']: \n", removeKeyDuplicates(objects, ["Language", "Name"]));
I would use the underscore module for JavaScript and the unique function in this scenario. Here is a sample array of data objects:
let data = [{
name: 'blah',
date: Date.now(),
language: "en"
},
{
name: 'noblah',
date: Date.now(),
language: 'es'
},
{
name: 'blah',
date: Date.now(),
language: 'en'
}];
Then we can use the unique function in the underscore library to only return a copy of the data that has unique values associated with the language key:
const result = _.unique(data, 'language');

convert nested object to one level up object in javascript

given json : -
{
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
}
desired json: -
{
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
I want to convert JSON with the help of lodash library of npm in javascript or suggest any other library,
it might be a silly question, Please explain it properly, I am a newbie in javascript and try to learn node.js. comment me if you need more explanation.
Thanks for help
You don't really need a library, you can just assign the property and delete the other.
However tokens is an array, which suggest there might be more than one. This will only take the first one (obj.tokens[0].token). Since objects can't have duplicate keys, you will only be able to have one token with your desired format (if that matters).
let obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
}
obj.token = obj.tokens[0].token
delete obj.tokens
console.log(obj)
There are a number of ways to solve this problem and no one "right" way. However, you may want to consider creating a new object, rather than mutating the original object. Objects are always passed by reference in JavaScript and it's easy to accidentally modify an object inside a function, not realizing that you just changed that object everywhere else it's referenced as well.
Since you mentioned it, here is a way to solve this with Lodash.
const obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
};
// create a new object without the tokens property
const newObj = _.omit(obj, 'tokens');
// get the first token object from the tokens array
const tokenObj = _.head(obj.tokens);
// get the token string from the token object, defaulting to empty string if not found
newObj.token = _.get(tokenObj, 'token', '');
console.log(newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Lodash is a great library and used by many projects. It can be especially helpful for new developers. For example, _.head(arr) will return undefined if arr is undefined. However, arr[0] would crash in the same scenario.
Here's one way to solve it without a library.
const obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
};
// create a copy of the original object.
// note that Object.assign will make a shallow copy of our object,
// so newObj.tokens will be a pointer to obj.tokens.
// in this instance, we don't care, as we are going to remove newObj.tokens anyway.
const newObj = Object.assign({}, obj);
// throw away the tokens property.
// OK to mutate newObj as we know it is not used anywhere else.
delete newObj.tokens;
// get the first token object from the tokens array.
// the (expectedArray || []) pattern ensures we have an array if obj.tokens is null or undefined.
const tokenObj = (obj.tokens || [])[0];
// get the token string from the token object.
// again, using the (expectedObject || {}) pattern in case tokenObj is null or undefined.
const token = (tokenObj || {}).token;
// create a new property called "token" on our newObj object.
// set it to our token value or an empty string if token is null or undefined.
newObj.token = token || '';
// of course, if you know the tokens array will always have a valid token object,
// you can simply use newObj.token = obj.tokens[0].token.
console.log(newObj);
Using destructuring assignment with "empty" representations of your types works nicely. transform produces a reliable output when tokens contains zero, one, or many { token: ... } values.
const emptyUser =
{ _id: 0, name: "", tokens: [] }
const emptyToken =
{ token: "" }
const toSingleTokenUser =
({ tokens: [ { token } = emptyToken ], ...u } = emptyUser) =>
({ ...u, token })
console .log
( toSingleTokenUser ({ _id: 1, name: "a", tokens: [ { token: "t" } ] })
// { _id: 1, name: "a", token: "t" }
, toSingleTokenUser ({ _id: 1, name: "a", tokens: [] })
// { _id: 1, name: "a", token: "" }
, toSingleTokenUser ({ _id: 1, name: "a", tokens: [ { token: "t1" }, { token: "t2" } ] })
// { _id: 1, name: "a", token: "t1" }
, toSingleTokenUser ({ foo: "bar", tokens: [ { token: "t" } ] })
// { foo: "bar", token: "t" }
)

Node.js/express parsing data and still getting back [object Object] in response and some data is missing

As stated above I am using NODE/Express backend and trying to parse out some data before I send it to the front-end.
I have an array of objects(items) and want to parse out a certain field in each item, particularly the description and the geolocation. It seems like it works just fine, but I have a couple of issues I am running into.
First I will show you one of the items to show you what it was before:
{
"_id": {
"$oid": "59925302e12872a81b28099e"
},
"offer": "19f5d9ef37b30311",
"txid": "389eb024f8869d787954c74d1653b8358e581cb4c81358361ffac662875bceec",
"expires_in": 13770133,
"expires_on": 1516531809,
"expired": false,
"height": "46411",
"category": "for sale",
"title": "Jack Garratt Signed Deluxe CD",
"quantity": "1",
"currency": "USD",
"sysprice": 415240000000,
"price": "35.00",
"ismine": false,
"commission": "0",
"offerlink": "false",
"private": "No",
"paymentoptions": 2,
"paymentoptions_display": "BTC",
"alias_peg": "sysrates.peg",
"description": "{\"description\":\"Signed, near mint double CD Only played a very few times\",\"media\":{\"defaultIdx\": 0,\"mediaVault\": [{\"mediaType\":\"img\",\"mediaURL\":\"http://i.imgur.com/bB7QjDR.jpg\"}]}}",
"alias": "Signed, near mint double CD Only played a very few times http://i.imgur.com/bB7QjDR.jpg",
"address": "1GR389Tki2LS3jScFUhrVxVnXdPdED5839",
"alias_rating_display": "0.0/5 (0 Votes)",
"offers_sold": 0,
"geolocation": "{\"coords\":{\"lat\":36.8518706,\"lng\":-123.5029326}}",
"alias_rating_count": 0,
"alias_rating": 0,
"safetylevel": 0,
"safesearch": "Yes",
"offerlink_seller": "",
"offerlink_guid": "",
"time": {
"$date": "1970-01-18T04:29:58.326Z"
},
"cert": "",
"__v": 0
}
Next I will show you how I parse the data I want. I particularly want a description geolocation and a new field media.
let newResults = [];
let updatedItem = {};
results.map((item, i) => {
const newDescription = JSON.parse(item.description);
const newGeolocation = JSON.parse(item.geolocation);
console.log(newGeolocation)
updatedItem = item;
updatedItem.geolocation = newGeolocation;
updatedItem.media = newDescription.media;
updatedItem.description = newDescription.description;
newResults.push(updatedItem);
return newResults;
});
console.log(newResults[24]);
Here is the result of console.log(newResults[24]):
{ _id: 59925302e12872a81b2809a3,
offer: '17fff08820c6da06',
txid: 'f27ec82c4cd694ecfdf061ebff7709a6154e39767595f7da08e4b2a40503c816',
expires_in: 26828208,
expires_on: 1529589884,
expired: false,
height: '276435',
category: 'for sale',
title: 'Marijuana Flavoured Vape E-Liquid 10ml 6mg',
quantity: '19',
currency: 'GBP',
sysprice: 1912000000,
price: '2.00',
ismine: false,
commission: '0',
offerlink: 'false',
private: 'No',
paymentoptions: 1,
paymentoptions_display: 'SYS',
alias_peg: 'sysrates.peg',
description: 'Marijuana Flavoured E-Liquid 10ml 6mg',
alias: 'Marijuana Flavoured E-Liquid 10ml 6mg',
address: '1DNeg3CrRFx6PuLcCry26p9y2XiTzTTFqw',
alias_rating_display: '0.0/5 (0 Votes)',
__v: 0,
offers_sold: 0,
geolocation: '[object Object]',
alias_rating_count: 0,
alias_rating: 0,
safetylevel: 0,
safesearch: 'Yes',
offerlink_seller: '',
offerlink_guid: '',
time: Sun Jan 18 1970 02:32:37 GMT-0600 (Central Standard Time),
cert: '' }
As you can see the data seems to have been parsed for the description, but the geolocation is giving me a weird [object Object] even though if I console log it inside the map it gives me each of the parsed data and they look fine.
Something else that I want to note here is that the media field is not even there. But if I were to console.log(newResults[24].media) it shows me the parsed data. But if I do try to access it on the front end like item.media I get undefined which is expected since it does not show up.
You are misusing map(). map() will return an object out of it. Try using something like this:
let newResults = results.map((item, i) => {
const {
media,
description
} = JSON.parse(item.description);
const geolocation = JSON.parse(item.geolocation);
return {
geolocation,
media,
description
};
});
console.log(newResults[24]);
If you want to tack these properties onto the item (without mutating the original item) you can use Object.assign() which will dump all the properties of the objects from the second argument onward into whatever the first argument is with priority given to later arguments.
In other words, we are going to return the value returned by the call to Object.assign({}, item, {...new props...}) and that call is going to create a new Object {} then dump all the properties from item into that new Object and then it is going to dump all the properties from {...new props...} on that first {} argument and will overwrite properties if they are already there.
let newResults = results.map((item, i) => {
const {
media,
description
} = JSON.parse(item.description);
const geolocation = JSON.parse(item.geolocation);
return Object.assign({}, item, {
geolocation,
media,
description
});
});
Additionally, when printing nested objects in node.js with console.log(), node will truncate the output rather than printing the whole arrary. Consider this code:
let tmp = [
{
foo: "Bar",
fizz: [
{
buzz: "hello"
}
]
}
];
console.log(tmp);
Will print:
[ { foo: 'Bar', fizz: [ [Object] ] } ]
The object is still fine, and if you try to dereference the nested object itself with console.log(tmp[0].fizz[0].buzz); You will get the output: hello.
Try
results.map((item, i) => {
const newDescription = JSON.parse(item.description);
const newGeolocation = JSON.parse(item.geolocation);
console.log(newDescription.media)
updatedItem = item;
updatedItem.geolocation = item.geolocation; //just assign geolocation
updatedItem.media = JSON.stringify(newDescription.media); //stringify the media object
updatedItem.description = newDescription.description;
newResults.push(updatedItem);
return newResults;
});

Categories