So im building an app mock up , upon sending a message I need to notify all the participants of the chat that they have an unread message, My participant type has a field called "unread" which is an array of objects like such
unread:[
{chatId:'13213', msgs:3},
{chatId:'132546', msgs:1}
];
chat id references to a unique conversation, and msgs number shows new messages sent , the length of msgs array is the number of unread msgs you have , what I want to do is , when a new msg is sent I want to loop through the unread array and
condition one Array is completely empty :
add an object to it
condition two array already has objects, then find the one that has the same chatId as the one I will pass in the function and increase the message count
condition three, array already has objects but not with the chatId I provided, in which case create a new object and add it to an existing array.
any ideas on how I can go about this?
I tried doing the following but it doesn't work
emp.unread.length < 1
? [{ chatId: chatId, unread: 1 }]
: emp.unread.map((cht) => {
if (cht.chatId === chatId) {
return {
...emp.unread,
chatId: chatId,
unread: cht.unread + 1,
};
} else {
return { ...emp.unread, chatId: chatId, unread: 1 };
}
}),
You can try using the if condition as below:
You can use filter/find to complete you tasks normally.There could still be other less resource consuming way but this way you will get your task done.
if(unread.length == 0 ){
//pushing the object
}else{
if(chechExistingChat(chatid)){
addOnExistingChat(chatId)
}
else{
//unread.push(new object)
}
}
function checkExistingChat(chatId){
let sameChatArray = unread.filter((item)=>{
return item.chatId == chatId
})
return !!sameChatArray.length
}
function addOnExistingChat(chatId){
let finalArray = unread.map((item)=>{
if(item.chatId == chatId){
return {...item,msgs:item.msgs+1}
}
return item
})
return finalArray
}
Related
Within each element in an array, there may or may not be a value that I need to grab. If the value is not in one element, I want to go to the next element to look for it. I'd like to know how to write the statement to do that in my Postman test. I already know how to get the values when they exist, but I want to go through each element until I find what I'm looking for to put in the variable.
I've googled how to write the code, but I'm new to this and I'm having trouble.
var jsonData = JSON.parse(responseBody);
postman.setGlobalVariable("Date", jsonData.array[0].field[1]);
if (postman.setGlobalVariable("Date", jsonData.array[0].field[1]) === ???
else (postman.setGlobalVariable("Date", jsonData.array[1].field[1]);)
Hi, Here is a sample response (thanks!): You can see the first element does not have the value, "NeedTheseDates" that I need to grab, but the second element does.
"SampleArray": [
{
"Date": "2019-05-18T00:00:00.0000000-04:00",
"NeedTheseDates": [],
"Anything": "data",
"OnlyDate": "2019-06-03T00:00:00.0000000-04:00"
},
{
"Date": "2019-06-16T00:00:00.0000000-04:00",
"NeedTheseDates": [
"2019-07-02T00:00:00.0000000-04:00",
"2019-07-03T00:00:00.0000000-04:00",
"2019-07-04T00:00:00.0000000-04:00",
"2019-07-05T00:00:00.0000000-04:00",
"2019-07-06T00:00:00.0000000-04:00",
"2019-07-07T00:00:00.0000000-04:00",
"2019-07-08T00:00:00.0000000-04:00",
"2019-07-09T00:00:00.0000000-04:00",
"2019-07-10T00:00:00.0000000-04:00",
"2019-07-11T00:00:00.0000000-04:00",
"2019-07-12T00:00:00.0000000-04:00"
],
Not very sure about the problem statement. So trying all combinations
If there are only two cases where the value could be (index 0 or 1)
let someDate = jsonData.array[0].field[1] === '???' ?
jsonData.array[0].field[1] : jsonData.array[1].field[1];
postman.setGlobalVariable('Date', someDate);
If the length of array is dynamic but the date you are looking for in field is always at index 1
let someDate;
jsonData.array.forEach((element) => {
element.field[1] === '???' && (someDate = element.field[1]);
});
postman.setGlobalVariable('Date', someDate);
This will traverse all the items irrespective of whether it finds the correct element before. You can use some to stop that
let someDate;
jsonData.array.some((element) => {
if (element.field[1] === '???') {
someDate = element.field[1]);
return true; // this will stop the loop
}
});
postman.setGlobalVariable('Date', someDate);
If the length of array is dynamic and field is also dynamic
let someDate;
jsonData.array.some((element) => {
element.field.some((oneDate) => {
if (oneDate === '???') {
someDate = oneDate;
return true; // this will stop the inner loop
}
});
if (someDate) {
return true; // this will stop the outer loop
}
});
postman.setGlobalVariable('Date', someDate);
I am creating a multipage application. When the user navigates to one of my pages componentDidMount triggers and currently generates 4 random numbers within a range I have specified and sends them through my reducer. This eventually comes back in the form of an array.
Within componentDidMount I have a loop to call my generateRandomNumber function four times. However, if I go to log the output array I get a blank array, which is the initial state for said reducer.
Logging the array in componentDidUpdate, or anywhere after the mount returns what I want it to but that doesn't help me in checking for duplicates as I cannot check for duplicates if I am checking against a blank array. Everything should be without delay, but there seems to be an issue with trying to read from this.props.currentUserList from within componentDidMount.
I need to verify that I am not adding two of the same user into my array, but I need the pre-check to all be done by the time this appears on-screen.
//gives me a random user from my array
generateRandomUser() {
return myArray[Math.floor(Math.random() * 100) + 1]
}
//sends 4 randomUsers through my actions to my reducers
generateNewID() {
let amountOfOptions = 4;
while (amountOfOptions > 0) {
let randomUser = this.generateRandomUser();
if (this.props.currentUserList.length === 0) {
this.props.setCurrentUser(randomUser);
} else {
//this never fires as currentUserList is somehow still == []
this.checkForDuplicates();
}
amountOfOptions--;
}
}
componentDidMount() {
this.generateNewID()
console.log(this.props.currentUserList)
//returns []
}
componentDidUpdate() {
console.log(this.props.currentUserList)
// returns [
// user2: {
// name: 'name'
// },
// user4: {
// name: 'name'
// },
// user28: {
// name: 'name'
// },
// user92: {
// name: 'name'
// },
// ]
}
I am not sure about the implementation of the array. However if the required output is to get 4 random users then instead of of calling setcurrentuser 4 times, you can generate 4 users and then set them at once.
generateNewID() {
let amountOfOptions = 4;
let randomUserList = [];
while (amountOfOptions > 0) {
let randomUser = this.generateRandomUser();
if (randomUserList.length === 0) {
randomUserList.push(randomUser);
} else {
//this never fires as currentUserList is somehow still == []
this.checkForDuplicates();
}
amountOfOptions--;
}
this.setCurrentUser(randomUserList);
}
I am using sails (0.11.0) running on nodejs (6.9.1). I am trying to construct an array by filling it through for loop. I would send this completed array in response to the client. I have tried various methods as suggested by people here on Stack Overflow, for example
the discussion here suggested
for (var i = yearStart; i < yearEnd+1; i++) {
arr.push(i);
}
On this discussion, it is suggested to use:
var array = calendars.map(function(item) {
return item.id;
});
console.log(array);
Similarly I tried many methods but I am coming across the same issue that during the loop, the array gets filled but as soon as the loop is completed, the array gets empty because of asynchronous process and therefore I can not send the response. To tackle with this I tried checking the index inside the loop body and send response from inside the loop body itself through
var userArray = [];
_.each(users, function(user, index){
MySQLConnector.query('CALL user_image (?)', [user.id], function(err, userImage){
if(err){
return res.json({"status":"some_error"});
}else{
userID = user.id
userImageID = userImage[0][0].id;
var userInfo = {
userID: userID,
userImageID: userImageID
}
userArray.push(userInfo)
if(index == users.length - 1){
res.json({selectedUsers: userArray});
}
}
});
});
I am initiating an empty userArray and then iterate through users object where each element of the object is characterized by name user and an index. Through a MySQL query I am fetching the userImage object and in each iteration, I am creating an object called userInfo that consists of userID and userImageID. I am pushing this object into userArray. And after each iteratio of the for loop (_.each), I check if last index is reached. Once last index is reached, the final array is sent as response before loop body is complete.
Here too I have an issue that the array body is not always completely filled. The reason is due to asynchronous process, the index does not always follow the order 0,1,2,3,4,.... and it can start with any number and can jump to any index in the next iteration, for example the first index to start would be 4, the second would be 0, third would be 2 and so on. This sequence would be different for every time we run this for loop. For a user, it will appear to be a total random process. Therefore if users.length is 8, and current index is randomly 7 at third iteration, the condition index == users.length - 1 will be met and response will be sent just with an array consisting of 3 elements rather than 8.
Can someone suggest me a better and robust way to fill an array through the for loop in nodejs and send that array in response, so that all items are included in the array in their original order?
As you are using node js , it is better to use any promises library like bluebird or async to handle Async requests.
The reason your loop is not working as expected is because as you've pointed out, due to async requests taking time to resolve for which _.each loop is not waiting.
Using bluebird, it can be done with Promise.map method which works as explained below from the documentaion :
Given an Iterable(arrays are Iterable), or a promise of an Iterable,
which produces promises (or a mix of promises and values), iterate
over all the values in the Iterable into an array and map the array to
another using the given mapper function.
Promises returned by the mapper function are awaited for and the
returned promise doesn't fulfill until all mapped promises have
fulfilled as well. If any promise in the array is rejected, or any
promise returned by the mapper function is rejected, the returned
promise is rejected as well.
Hence, Using Promise.map your code can be updated like below :
var Promise = require("bluebird");
return Promise.map(users, function(user, index){
return MySQLConnector.query('CALL user_image (?)', [user.id], function(err, userImage){
if(err){
return Promise.reject({"status":"some_error"});
}else{
userID = user.id
userImageID = userImage[0][0].id;
var userInfo = {
userID: userID,
userImageID: userImageID
}
return userInfo;
}
});
})
.then(function (usersArray){
res.json({selectedUsers: usersArray});
})
.catch(function (err){
res.json(err);
});
You can execute loops with functions with callbacks synchronously using SynJS:
var SynJS = require('synjs');
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'tracker',
password : 'tracker123',
database : 'tracker'
});
function myFunction1(modules,connection,users) {
var ret=[];
for(var i=0; i<users.length; i++) {
connection.query("SELECT CONCAT('some image of user #',?) AS userImage", [users[i]], function(err, rows, fields) {
if (err) throw err;
ret.push({
id: users[i],
image: rows[0].userImage
});
modules.SynJS.resume(_synjsContext); // <-- indicate that callback is finished
});
SynJS.wait(); // <-- wait for callback to finish
}
return ret;
};
var modules = {
SynJS: SynJS,
mysql: mysql,
};
var users = [1,5,7,9,20,21];
SynJS.run(myFunction1,null,modules,connection,users,function (ret) {
console.log('done. result is:');
console.log(ret);
});
Result would be following:
done. result is:
[ { id: 1, image: 'some image of user #1' },
{ id: 5, image: 'some image of user #5' },
{ id: 7, image: 'some image of user #7' },
{ id: 9, image: 'some image of user #9' },
{ id: 20, image: 'some image of user #20' },
{ id: 21, image: 'some image of user #21' } ]
In my users profile collection I have array with image objects in it.
A user can have a max of 3 images in their profile collection. If the user has 3, throw an error that the maximum has been reached. The user has the option to remove an image themselves in the frontend.
I thought the solution would be to check the length of the array with $size. if it's less then 3, insert the image, else throw error.
I'm using the tomi:upload-jquery package.
client:
Template.uploadImage.helpers({
uploadUserData: function() {
return Meteor.user();
},
finishUpload: function() {
return {
finished: function(index, fileInfo, context) {
Meteor.call('insert.profileImage', fileInfo, function(error, userId) {
if (error) {
// todo: display modal with error
return console.log(error.reason);
} else {
// console.log('success ' +userId);
// console.log('success ' + fileInfo);
}
});
}
};
}
});
The method (server) I use:
'insert.profileImage': function(postImage) {
check(postImage, Object);
// check array profile.images max 3
Meteor.users.update(this.userId, {
$push: {
'profile.images': postImage
}
});
},
You may do it with a function using the $where operator:
'insert.profileImage': function(postImage) {
var updateResults;
check(postImage, Object);
updateResults = Meteor.users.update(
{
_id : this.userId,
$where : 'this.profile.images.length < 3' //'this' is the tested doc
},
{
$push: {
'profile.images': postImage
}
});
if(updateResults === 0) {
throw new Meteor.Error('too-many-profile-images',
'A user can only have up to 3 images on his/her profile');
}
},
The Mongo docs warns about potential performance issues (if you run a JavaScript function on all documents of the store, you're in for bad surprises) but since we also search by _id I guess it should be fine.
This way, the update just doesn't run if the user has too many images. You can also check the number of affected document (the return value of the update) to know if something happened. If nothing (returns 0) happened, there's not many possibilities: The user has too many images.
Use the $exists operator to check the existence of all documents that have at least a fourth profile image array element (index position 3) with the dot notation. For example you could use it to check whether the size of the profile.image array is greater than 3 with the find() method as follows:
var hasSizeGreaterThanThree = Meteor.users.find(
{
'_id': this.userId,
'profile.image.3': { '$exists': true }
}).count() > 0;
So you could use that in your code as:
'insert.profileImage': function(postImage) {
check(postImage, Object);
// check array profile.images max 3
var hasSizeGreaterThanThree = Meteor.users.find(
{
'_id': this.userId,
'profile.image.3': { '$exists': true }
}).count() > 0;
if (!hasSizeGreaterThanThree){
Meteor.users.update(this.userId, {
$push: {
'profile.images': postImage
}
});
}
},
I try to iterate throug an array of ids and make a ajax request for each id. subsequentely each response object is pushed in an array/ so far no problem, however, the problem starts when i try to access the responses in the array. the strange thing is that in the console log the responses are shown (ouside the array though, see below) but the properties of the array objects are empty/ it seems i generated an empty object with some data attached to it/ my question is how can i access the objects that are in (or not in?) the array
var getAssoc = {
returnProds: function (idCache) {
var id = idCache;
var prodData = [];
var counter = id.length;
$.each(id, function (i) {
$.ajax({
url: "myurl.php?",
data: {
'id': id[i]
},
success: function (data) {
prodData[i] = data;
counter--;
if (counter === 0) console.log(prodData);
},
})
});
}
};
console log looks like this. testing for number of properties returns 0
[]
0 Object { array={...}}
1 Object { array={...}}
2 Object { array={...}}
3 Object { array={...}}
In you success callback Try parsing the response coming from your server:
jQuery.parseJSON(data);