So I'm a beginner to js and I have a table of users in a json file and I'm making an account delete feature. I have a find set up to find the user and it works fine but I can't figure out how to make it delete the user from the file, any help would be appreciated!
Json:
{
"users": [
{
"name": "ImBattleDash",
"Id": "780748c5d4504446bbba3114ce48f6e9",
"discordId": "471621420162744342",
"dateAdded": 1548295371
}
]
}
JS:
function findJson() {
fs.readFile('./linkedusers.json', 'utf-8', function (err, data) {
if (err) message.channel.send('Invalid Code.')
var arrayOfObjects = JSON.parse(data)
let findEntry = arrayOfObjects.users.find(entry => entry.discordId == myCode)
let linkEmbed = new Discord.RichEmbed()
.setTitle('Account unlinked!')
.setDescription('Link your account by friending "BattleDash Bot" on Fortnite and then input the code you get messaged by typing "!link <code>"!')
.setColor('#a900ff');
message.channel.send({embed: linkEmbed});
})
}
EDIT: Not sure if it's an array or a table I don't know a lot about json
You need to use:
Array#find to find a given user by some given criteria.
Array#indexOf to get the index of the found user in users
Array#splice to drop one element starting from the index given by Array#indexOf:
const input = {
"users": [
{
"name": "ImBattleDash",
"Id": "780748c5d4504446bbba3114ce48f6e9",
"discordId": "471621420162744342",
"dateAdded": 1548295371
}
]
}
const removeUser = (criteria, users) =>
users.splice (users.indexOf (users.find (criteria)), 1)
removeUser (
({ Id, discordId }) =>
Id == '780748c5d4504446bbba3114ce48f6e9'
&& discordId == '471621420162744342',
input.users
)
// Output: 0 <-- User has been removed!
console.log(input.users.length)
About persisting the change, it's just about calling JSON.stringify (input) and then just write the contents to the desired output file. See this other Q&A: Writing files in Node.js
With great help from Cat and Matias I came up with this code that works!
function findJson() {
fs.readFile('./linkedusers.json', 'utf-8', function (err, data) {
if (err) message.channel.send('Invalid Code.')
var arrayOfObjects = JSON.parse(data)
let findEntry = arrayOfObjects.users.find(entry => entry.discordId == myCode)
const input = arrayOfObjects;
const removeUser = (criteria, users) =>
users.splice (users.indexOf (users.find (criteria)), 1)
removeUser (
({ Id, discordId }) =>
Id == findEntry.Id
&& discordId == findEntry.discordId,
input.users
)
console.log('unlinked')
fs.writeFile('./linkedusers.json', JSON.stringify(arrayOfObjects, null, 4), 'utf-8', function(err) {
if (err) throw err
console.log('Done!')
})
let linkEmbed = new Discord.RichEmbed()
.setTitle('Account unlinked!')
.setDescription('Link your account by friending "BattleDash Bot" on Fortnite and then input the code you get messaged by typing "!link <code>"!')
.setColor('#a900ff');
message.channel.send({embed: linkEmbed});
})
}
Here's a quick tutorial for you:
"Users" would be either an array (using []) or a javascript object (using {}), your choice. There won't be any actual tables unless you use a database instead of a JSON file (although if your JSON expression is as simple as your example, you could almost think of it as a table.) -- And actually, a third option would be to use the javascript Map type, which is like a beefed-up object, but I won't address that here.
While using an array would make it a bit easier to retrieve a list of data for all users (because arrays are simpler to iterate through), using an object would make it considerably easier to retrieve data for a single user (since you can directly specify the user you want by its key instead of needing to loop through the whole array until you find the one you want.) I'll show you an example that uses an object.
The individual user in your sample code is an example of a javascript object. JSON lets you convert an object to a string (for storage, I/O, and human readability) and back to an object (so javascript can understand it). You use the JSON.stringify() and JSON.parse() methods, respectively for these conversions. The string has to be JSON-formatted or this won't work, and your example is almost in JSON format.
To comply with JSON formatting, you could structure a Users object as follows. (Of course we're looking at the stringified version because mere humans can't easily read an "actual" javascript object):
"Users": { // Each individual user is a property of your users object
"780748c5d4504446bbba3114ce48f6e9": // The Id is the key in the "key/value pair"
{ // The individual user object itself is the value in the key/value pair
// Id is duplicated inside user for convenience (not necessarily the best way to do it)
"id": "780748c5d4504446bbba3114ce48f6e9",
"name": "ImBattleDash", // Each property of the user is also a key/value pair
"discordId": "471621420162744342", //Commas separate the properties of an object
"dateAdded": "1548295371" // All property values need double quotes for JSON compatibility
}, // Commas separate the properties (ie the individual users) of the users object
"446bbba3114ce48f6e9780748c5d4504": // This string is the second user's key
{ // This object is the second user's value
"id": "446bbba3114ce48f6e9780748c5d4504",
"name": "Wigwam",
"discordId": "162744342471621420",
"dateAdded": "1548295999"
}
}
Once you retrieve the string from storage, you convert it to an object and delete a user as follows. (This is broken down into more steps than necessary for clarity.):
let usersObject = JSON.parse(stringRetrievedFromFile);
let userId = "780748c5d4504446bbba3114ce48f6e9";
let userToModifyOrDelete = usersObject[userId];
delete userToModifyOrDelete;
To change the user's discordId instead, you would do:
let discordId = userToModifyOrDelete.discordId; // Not necessary, just shows how to retrieve value
let newDiscordId = "whateverId";
userToModifyOrDelete.discordId = newDiscordId;
And you'd convert the object back into a string to store in your file with:
JSON.stringify(usersObject);
Hopefully that's almost all you need to know about JSON!
Related
i want to make a search in a json file by query
Example:
My json file:
[{
"Id":1,
"name":"test"
},
{
"Id":2,
"name":"test"
}]
And if i search {"name":"test"} i get the full objects whos name is test
ADD: I misspoke its the user who enter the query how can i get the key and the value from the query {key:value} and the user can entre multiple keys and values (like the search in atlas mongodb)
UP!!
As per your question you are using JSON inside of an array.
So you can simply filter the array to find JSON which contains name="test"
Follow the below step:
let userArray = [{"Id":1,"name":"test"},{"Id":2,"name":"test"}]
const filteredUser = userArray.filter((user) => user.name === "test")
Try something simple:
var myjson ='[{"Id":1,"name":"test"},{"Id":2,"name":"test"},{"Id":3,"name":"nottest"}]';
var slag = JSON.parse(myjson).filter(doc => doc.name === 'test');
console.log(slag);
I am looping through a collection of blog posts to firstly push the username and ID of the blog author to a new array of arrays, and then secondly, count the number of blogs from each author. The code below achieves this; however, in the new array, the username and author ID are no longer separate items in the array, but seem to be concatenated into a single string. I need to retain them as separate items as I need to use both separately; how can I amend the result to achieve this?
var countAuthors = [];
blogAuthors = await Blog.find().populate('authors');
blogAuthors.forEach(function(blogAuthor){
countAuthors.push([blogAuthor.author.username, blogAuthor.author.id]);
})
console.log(countAuthors);
// Outputs as separate array items, as expected:
// [ 'author1', 5d7eed028c298b424b3fb5f1 ],
// [ 'author2', 5dd8aa254d74b30017dbfdd3 ],
var result = {};
countAuthors.forEach(function(x) {
result[x] = (result[x] || 0) + 1;
});
console.log(result);
// Username and author ID become a single string and cannot be accessed as separate array items
// 'author1,5d7eed028c298b424b3fb5f1': 15,
// 'author2,5dd8aa254d74b30017dbfdd3': 2,
Update:
Maybe I can explain a bit further WHY on what to do this. What I am aiming for is a table which displays the blog author's name alongside the number of blogs they have written. However, I also want the author name to link to their profile page, which requires the blogAuthor.author.id to do so. Hence, I need to still be able to access the author username and ID separately after executing the count. Thanks
You could use String.split().
For example:
let result = 'author1,5d7eed028c298b424b3fb5f1'.split(',')
would set result to:
['author1' , '5d7eed028c298b424b3fb5f1']
You can then access them individually like:
result[1] //'5d7eed028c298b424b3fb5f1'
Your issue is that you weren't splitting the x up in the foreach callback, and so the whole array was being converted to a string and being used as the key when inserting into the results object.
You can use array destructuring to split the author name and blog id, and use them to optionally adding a new entry to the result object, and then update that result.
countAuthors = [
['author1', 'bookId1'],
['author2', 'bookId2'],
['author1', 'bookId3'],
['author1', 'bookId4'],
['author2', 'bookId5']
]
var result = {};
countAuthors.forEach(([author, id]) => {
if (result[author] === undefined) {
result[author] = {count: 0, blogIds: []};
}
result[author].count += 1;
result[author].blogIds.push(id);
});
console.log(result);
I am preparing a weather app that gives suggestion list as we enter an input city name.
Json file is in this format:
{"coord":{"lon":-0.13,"lat":51.51},
"weather":[{"id":300,"main":"Drizzle","description":"light intensity drizzle","icon":"09d"}],
"base":"stations",
"main":{"temp":280.32,"pressure":1012,"humidity":81,"temp_min":279.15,"temp_max":281.15},
"visibility":10000,
"wind":{"speed":4.1,"deg":80},
"clouds":{"all":90},"dt":1485789600,
"sys":{"type":1,"id":5091,"message":0.0103,
"country":"GB",
"sunrise":1485762037,
"sunset":1485794875},
"id":2643743,
"name":"London",
"cod":200}
So my code for that functionality is:
inputcity.addEventListener("input",()=>getweather(inputcity.value));
const getweather=async searchtext=>{
const res=await fetch("https://api.openweathermap.org/data/2.5/weather?q="+inputcity.value+"&units=metric&appid=78a661b7c335021c7d85065aea3673be");
const cities= await res.json();
let matches=cities.filter(city=>{
const regex=new RegExp(`^${searchtext}`,'gi');
return city.name.match(regex);
});
console.log(matches);
};
What I want is to show a list of city names starting with same letters.
But it's showing error the following error:
*Uncaught (in promise)TypeError: cities.filter is not a function*
because this api gives data in nested objects not in array of objects.
How can get my code working using filter or any method?
Because i don't have 50 reputation to leave a comment on the comment section.
I will just leave my comments here, so you can got an idea how to do it.
Your code that fetch the API's from https://api.openweathermap.org/data/2.5/weather?q="+inputcity.value+"&units=metric&appid=78a661b7c335021c7d85065aea3673be is only returning data for 1 city.
The returned data is also not a ARRAY, It's a JSON object.
See here for better viewing of your data : https://codebeautify.org/jsonviewer/cb13b4bd
For your idea about suggestion list on city name when users inputted the data, is not on their api's feature.
You should make a array for the city name lookup and shows the suggestion with .startsWith(user.input).
Example super inefficient code to do that :
const userinput = "a";
var city = ["aaa", "abc", "bca", "cba", , "ccc"];
city.forEach(searchsuggestion);
function searchsuggestion(value, index) {
if (value.startsWith(userinput)) {
console.log("Suggestion : " + value);
}
else {
return;
}
}
Your Console output for the above code should be :
Suggestion : aaa
Suggestion : abc
{"__v":0,"_id":{"$oid":"55f13d34258687e0bb9e4385"},"admin":true,"email":"emaple1#gmail.com","last_login":"11:25:24 AM","name_surname":"user1","password":"qwerty123"}
{"__v":0,"_id":{"$oid":"55ef49dd5d610eab18719deb"},"admin":true,"email":"emaple2#gmail.com","last_login":"12:25:24 AM","name_surname":"user2","password":"qwerty123"}
{"__v":0,"_id":{"$oid":"55f0173bb3322bf560724fd1"},"admin":true,"email":"emaple3#gmail.com","last_login":"10:25:24 AM","name_surname":"user3","password":"qwerty123"}
Hello, I working in nodeJS file and there I have a collection of JSON objects and I would like to make a search through it. For each user from this list I need to compare the field "last_login" .
I am new to nodeJS can someone help? Thank you!
This is what i have tried:
User.find({}, {last_login: }, function(err, docs) {
if (err) {
return res.json({ success: false, message: 'Failed to display last logins.' });
}
docs.forEach(function(doc, index) {
res.json({success: true, message: 'time of last login', last_login: doc.last_login});
})
//res.json(users);
});
});
Where last_login is a field in the User object and basically I need to iterate over all users in the db and extract only the last_login and display in in the response.I don’t know what value to put in the find() inside the curly braces
this is the part where I am stuck
I’ve slightly changed the function and it returns a JSON object containing the info about one user that is matched with the search query. The problem is, the console displays the result, as a whole object, although I want to get only a specific key value pair and namely last_login: value
function searchByUserName(name_surname) {
return list.filter(function(user) {
return user.name_surname === name_surname;
});
}
var a = searchByUserName('user1');
for (last_login in a ) {
if (a.hasOwnProperty(last_login)) {
console.log("last_login" + "=" + JSON.stringify(a[last_login]))
}
}
Can you tell me please, what change to make in order to get only the last_login key
here is a sample result from the console.log() that I receive:
last_login={"__v":0,"_id":{"$oid":"55f13d34258687e0bb9e4385"},"admin":true,"email":"emaple1#gmail.com","last_login":"11:25:24 AM","name_surname":"user1","password":"qwerty123"}
although I want last_login = “last_login”: 11:25:24 AM
Assuming it's an array of objects like bellow.
var users = [{"__v":0,"_id":{"$oid":"55f13d34258687e0bb9e4385"},"admin":true,"email":"emaple1#gmail.com","last_login":"11:25:24 AM","name_surname":"user1","password":"qwerty123"},
{"__v":0,"_id":{"$oid":"55ef49dd5d610eab18719deb"},"admin":true,"email":"emaple2#gmail.com","last_login":"12:25:24 AM","name_surname":"user2","password":"qwerty123"},
{"__v":0,"_id":{"$oid":"55f0173bb3322bf560724fd1"},"admin":true,"email":"emaple3#gmail.com","last_login":"10:25:24 AM","name_surname":"user3","password":"qwerty123"}];
you can create a function like bellow
function searchByLastLogin(last_login) {
return users.filter(function(user) {
return user.last_login === last_login;
});
}
console.log(searchByLastLogin("12:25:24 AM"));
console.log(searchByLastLogin("10:25:24 AM"));
console.log(searchByLastLogin("11:25:24 AM"));
It will retrun a array of users whose last_login will match to given parameter last_login.
Update
What I understood from your comment bellow, you want last logins of every user.
For that you can do something like bellow
var last_logins = users.map(function(user){
return user.last_login;
});
console.log(last_logins); //prints [ '11:25:24 AM', '12:25:24 AM', '10:25:24 AM' ]
References
filter | map
I don’t know what value to put in the find() inside the curly braces this is the part where I am stuck
If I understand correctly, you only want to get the last_login field for the user model, and that's what you're struggling with ?
According to the documentation, this should work if you only want to get that field :
User.find({}, {last_login:1, _id:0})
In my web app , i am using jquery ui autocomplete which data are stored in the database (Mysql).
In this application, i have the administration official data And i enable the users to enter their own data. Data will be displayed in the autocomplete drop down list .
The administration data are limited and never change thus are preloaded and cached in memory, however the user data aren't (since user data grows exponentially and there is no point of using a database if all is to be cached in memory).
So i am doing multi levels caching in my web app, of which, i am caching autocomplete's user data on the client side (instead of getting them from db on each search).
The scenario is as follow:
When the app loads, the admin data (that are preloaded in memory) are loaded and cached in a JS object to be used in the autocomplete mechanism.
Thus when a user searches for a word, it will check the admin data JS object and if it can't find it, it will go to db and find it in user data.
So for the case of searching user's data in db, What i am doing right now is the following:
$( "#search" ).autocomplete({
source:function(request, response) {
var results = $.ui.autocomplete.filter(data, request.term);
if (request.term.toUpperCase() in autocomplete_cache) {
response($.map(autocomplete_cache[request.term.toUpperCase()], function(item) {
return {value: item.members.name, md5: item.members.ID}
}))
return;
}
where autocomplete_cache is a javascript object:
var autocomplete_cache = {};
// ...it gets filled everytime a new $.post gets new data
...autocomplete_cache[request.term.toUpperCase()] = data;
For the moment, it is caching the exact term searched by a user.
For example, if a user writes "ABCD" and which is not already cached :
--> go to the database (MySQL) do :"WHERE term Like %ABCD%"
--> autocomplete_cache["ABCD"] = "data parsed from mysql"
So if the same USER now retypes "ABCD" it will get it from the autocomplete_cache Object. However if the USER type "ABC" it won't get it from the cache object because of the line:
if (request.term.toUpperCase() in autocomplete_cache)
So what i would like to do is to match what the User types in the cache, so in this scenario if the User types "ABC" (which is contained in cache's "ABCD" String) , the autocomplete will build a drop down list containing "ABCD".
Is there a way of doing that? the reason for this requirement instead of finding the exact String index in the cache object , it will find a wider range and thus limit probabilities of needing to go to db to find the new matches.
Instead of looking for a specific key, test each key whether the term is a substring:
var term = request.term.toUpperCase();
for (var key in autocomplete_cache) {
if (key.indexOf(term) > -1) {
// term is contained in key
}
}
And instead of calling response on the first match, collect all matches’ items in an additional array and call response at the end:
var term = request.term.toUpperCase(),
items = [];
for (var key in autocomplete_cache) {
if (key.indexOf(term) > -1) {
items.merge($.map(autocomplete_cache[key], function(item) {
return {value: item.members.name, md5: item.members.ID}
});
}
}
if (items.length > 0) response(items);
You might also want to remove any duplicates in items and sort the resulting items before calling response:
var term = request.term.toUpperCase(),
items = [],
index = {};
for (var key in autocomplete_cache) {
if (key.indexOf(term) > -1) {
$.each(autocomplete_cache[key], function(item) {
var id = item.members.ID;
if (!index[id]) {
items.push({value: item.members.name, md5: item.members.ID});
index[id] = true;
}
});
}
}
items.sort(function(a, b) { return a.name.localeCompare(b.name); });
if (items.length > 0) response(items);