I have the following result from MongoDB.aggregate:
[{
_id: ObjectId(1),
_author: ObjectId(2),
comments: [
{
_author: ObjectId(2),
text: '...'
},
{
_author: ObjectId(3),
text: '...1'
},
{
_author: ObjectId(3),
text: '...2'
}...
]
}...]
I need to get all unique authors _author field from all elemnts (including nested):
var uniqAuthors = magicFunction(result) // [ObjectId(2), ObjectId(3)] ;
What is the best and compact way to make it with pure JS?
Array.prototype.reduce can help you:
var unique = result[0].comments.reduce(function(uniqueAuthors, comment) {
if (uniqueAuthors.indexOf(comment._author) === -1) {
uniqueAuthors.push(comment._author);
}
return uniqueAuthors;
}, []);
//Verify the author from document
if (unique.indexOf(result[0]._author) === -1) {
uniqueAuthors.push(result[0]._author);
}
Related
I have an array which contains following objects.
myArray = [
{ item: { id: 111557 } },
{ item2: { id: 500600 } }]
and I have a variable
targetItemID = '111557'
Note that one is string, and the ones in array are numbers. I'm trying to get the object having the correct item id.
Here is what I have tried,
myArray = [
{ item: { id: 111557 } },
{ item2: { id: 500600 } }]
targetItemID = '111557'
var newArray = myArray.filter(x => {
console.log(x.item.id.toString())
console.log(targetItemID.toString())
x.item.id.toString() === itemID.toString()
})
console.log(newArray);
I expect all matching objects to be added to 'newArray'. I tried to check the values before comparison, They are both strings, they seem exactly same, but my newArray is still empty.
Your second object doesn't have an item property and should.
You need a return in your filter function.
You must compare x.item.id against targetItemID, not itemID. Since you are using console.log() you would have seen and error of itemID id not defined ;).
myArray = [
{ item: { id: 111557 } },
{ item: { id: 500600 } }
];
targetItemID = '111557'
var newArray = myArray.filter(x => {
//console.log(x.item.id.toString())
//console.log(targetItemID.toString())
return x.item.id.toString() === targetItemID.toString();
});
console.log(newArray);
There are a few issues here. First, not all your objects have an item property, so you'll need to check it exists. Second, you're comparing them against a non-existent itemID instead of targetItemID, and finally, and #bryan60 mentioned, if you open a block in an anonymous lambda, you need an explicit return statement, although, to be honest, you really don't need the block in this case:
var newArray =
myArray.filter(x => x.item && x.item.id && x.item.id.toString() === targetItemID)
you need to return for filter to work:
return x.item.id.toString() === itemID.toString();
eslint keeps showing me a prefer-restructuring error. However, I'm don't really know how array destructuring works and would love some help.
These are the two lines returning an error:
word.results.inCategory = word.results.inCategory[0];
// and:
word.results = word.results.filter(
(res) =>
Object.keys(res).includes('partOfSpeech') &&
Object.keys(res).includes('inCategory')
)[0];
Again, I'm not very knowledgable in this area, so any help on how to fix/simplify this specifically would be appreciated!
EDIT: Here is an example object for reference:
{
word: 'midrash',
results: [{
definition: '(Judaism) an ancient commentary on part of the Hebrew scriptures that is based on Jewish methods of interpretation and attached to the biblical text',
partOfSpeech: 'noun',
inCategory: ['judaism'],
typeOf: [ 'comment', 'commentary' ]
},
{
definition: 'something',
partOfSpeech: 'something',
}],
syllables: { count: 2, list: [ 'mid', 'rash' ] },
pronunciation: { all: "'mɪdrɑʃ" },
frequency: 1.82
}
To get the value of inCategory you should use the destructuring assignment as follow:
const obj = {
word: 'midrash',
results: {
definition: '(Judaism) an ancient commentary on part of the Hebrew scriptures that is based on Jewish methods of interpretation and attached to the biblical text',
partOfSpeech: 'noun',
inCategory: 'judaism',
typeOf: [ 'comment', 'commentary' ]
},
syllables: { count: 2, list: [ 'mid', 'rash' ] },
pronunciation: { all: "'mɪdrɑʃ" },
frequency: 1.82
}
let {results: {inCategory: category}} = obj;
//Now you can assign the category to word.results.inCategory
console.log(category);
For the filter approach, I suggest using the function Array.prototype.find
word.results = word.results.find(
(res) =>
Object.keys(res).includes('partOfSpeech') &&
Object.keys(res).includes('inCategory')
);
If you are already sure that your data structure is correct and both word.results.inCategory and word.results are arrays then this is how you do it:
const { results:{ inCategory: [inCategory] }} = word;
word.results.inCategory = inCategory;
// and:
const [results] = word.results.filter(
(res) =>
Object.keys(res).includes('partOfSpeech') &&
Object.keys(res).includes('inCategory')
);
word.results = results;
Of course in the second destructing when you filter you can just use find that allows you directly set the word.results without destructing:
word.results = word.results.find(
(res) =>
Object.keys(res).includes('partOfSpeech') &&
Object.keys(res).includes('inCategory')
);
I have the following object:
[ { id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-runscripts2',
name: 'shutdown-computevm-runscripts2' },
{ id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-packer',
name: 'shutdown-computevm-packer' } ]
I am trying to write a script that does something if it can't find a specific value in the name key of any of this object.
Example: shutdown-computevm-test
If there is no name anywhere in this object that matches this value, then I want my code to do something.
I'm new to nodejs, I tried things like includes(), indexOf etc, but these are either not the correct ways to do it or I never got the syntax right.
Any hints are appreciated.
Something like this should work for you;
const result = [ { id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-runscripts2',
name: 'shutdown-computevm-runscripts2' },
{ id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-packer',
name: 'shutdown-computevm-packer' } ];
const found = result.some((part) => part.name === 'shutdown-computevm-test');
if (! found) {
// do something here
}
I prefer it to filter as it won't wait to iterate over all items in the array and will shortcut as soon as it is found.
Use Array.prototype.find()
const arr = [ { id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-runscripts2',
name: 'shutdown-computevm-runscripts2' },
{ id:
'/subscriptions/resourcegroups/coco-test/providers/microsoft.devtestlab/schedules/shutdown-computevm-packer',
name: 'shutdown-computevm-packer' } ]
let rs = arr.find(item => item.name === 'shutdown-computevm')
let rs2 = arr.find(item => item.name === 'shutdown-computevm-runscripts2')
console.log(rs) // undefined
console.log(rs2) // obj
I have two values I need to match as you can see in the picture below:
I tried something like this:
const index = state.locks.users.findIndex(
stateUser => stateUser._id === action.payload.customerPayload.accessid
But I’m getting the error:
findIndex of undefined.
And I guess that’s because of locks being an array.
But I’m really uncertain how to fix this issue. Should I have multiple findIndexes? One for the lock and one for to match the users?
Thanks for reading my post. And I appreciate all the help I can get.
The code snippet should be
let itemIndex = -1;
state.locks.map((lock) => {
lock.users.findIndex(...)
});
Assuming state is an object containing locks array.
My suggestion to you is do a double for loop (as you've already figured) to get the user object that you need.
Consider the following snippet (adjust to your data structure):
let state = {
locks: [
{
users: [
{ _id: '123' },
{ _id: '456' }
]
},
{
users: [
{ _id: '678' },
{ _id: '789' }
]
},
]
};
function getUserObjByID(stateObj, userID) {
for (let usersObject of state.locks) {
for (let user of usersObject.users) {
if (user._id === userID) {
return user;
}
}
}
}
let myObj = getUserObjByID(state, '678');
console.log(myObj);
So it works now. What I had to do with my reducer was this:
case 'REMOVE_USER':
return {
...state,
locks: state.locks.map(lock => {
return {
...lock,
users: lock.users
? lock.users.filter(
user => user._id != action.payload.customerPayload.accessid
)
: []
}
})
}
Let's say I have an array of emails:
['a#gmail.com', 'b#gmail.com', 'c#gmail.com']
I need to convert it into an array of objects that looks like this:
[
{
id: 'a#gmail.com',
invite_type: 'EMAIL'
},
{
id: 'b#gmail.com',
invite_type: 'EMAIL'
},
{
id: 'c#gmail.com',
invite_type: 'EMAIL'
}
]
In order to do that, I have written the following code:
$scope.invites = [];
$.each($scope.members, function (index, value) {
let inviteMember = {
'id': value,
invite_type: 'EMAIL'
}
$scope.invites.push(inviteMember);
});
Is there any better way of doing this?
Since you're already using jQuery, you can use jQuery.map() like this:
var originalArray = ['a#gmail.com', 'b#gmail.com', 'c#gmail.com']
var newArray = jQuery.map(originalArray, function(email) {
return {
id: email,
invite_type:'EMAIL'
};
});
jQuery.map() translates all items in a given array into a new array of items. The function I am passing to jQuery.map() is called for every element of the original array and returns a new element that is written to the final array.
There is also the native Array.prototype.map() which is not supported in IE8. If you're not targeting IE8 or if you use a polyfill, then you can use the native .map():
var newArray = originalArray.map(function(email) {
return {
id: email,
invite_type:'EMAIL'
};
});
This pattern
targetArray = []
sourceArray.forEach(function(item) {
let x = do something with item
targetArray.push(x)
})
can be expressed more concisely with map:
targetArray = sourceArray.map(function(item) {
let x = do something with item
return x
})
in your case:
$scope.invites = $scope.members.map(function(value) {
return {
id: value,
invite_type: 'EMAIL'
}
});