So I have a file with multiple objects like this:
{
"order":{
"identifier":"B409908375",
"timeCreated":"2018-11-17T18:27:14.423335",
"totalPrice":10.000000000000000000000000000,
"payer_identity":{
"identifier":"K396677386",
"firstName":"Erika",
"lastName":"Mustermann",
"email":"testbuyer#mail.com",
"isEmailVerified":true,
"countryCode3Letter":"DEU"
},
"paymentProviderId":1,
"runtimeLengthDays":-1,
"runtimeOptionCustomIdentifier":"7fbdc628-893c-4499-844c-7a8c7ecaf325",
"productSku":"nd79z8jinqmkmtewfrb5"
},
"license":{
"productSku":"nd79z8jinqmkmtewfrb5",
"issuedToIdentifier":"K396677386",
"validFrom":"2018-11-17T18:27:21.21126",
"validUntil":"9999-01-01T00:00:00",
"isPermanent":true,
"keyIdentifier":"6b3d646f-cb20-4fc5-b520-e53227379407",
"isActive":true
}
}
I am trying to do a license check, so look for the keyIdentifier and see if it matches an input through a form. The input returns {license: "input"} and the result returns {order: {…}, license: {…}}. So yeah I want to check if input value can be found in the result/object.
I don't know if you aim to write your own function to do this from scratch or you want to use built in functions? If you don't have any preferences, you should be able to achieve this like:
const objects = [{object values>}, ...];
function getKeyIdObject(id) {
return objects.find(current => current.license.keyIdentifier === id);
}
getKeyIdObject ('<insert id here>');
This will return the matching object or null if not found. If you want to adjust what you return, you can also add .map(..) to adjust this.
So yeah I want to check if input value can be found in the result/object.
It sounds like you have no idea what is the key name where license number is being stored. But you have a clear name keyIdentifier contained into license breanch, so value can be easily get buy {}.license.keyIdentifier. If you try to do all that on fly you can just put both responses (input / result) into variables and then check if key is correct like this:
const keyFromInput = // here is what you get from input
const result = // here is {order: {…}, license: {…}}
if (keyFromInput === result.license.keyIdentifier) {
//here is what to do if key is correct
} else {
//here is what to do if key is wrong
}
Hope I got you right and you will find this helpful.
Related
I have been trying to figure out how have a form submit which then checks all the data in the form against JSON array data to determine if an object which matches all the input is already present. To start, here is my sample JSON data:
[
{
"ASIN":"B0971Y6PQ3",
"price":"13.99",
"email": "test#gmail.com"
},
{
"ASIN":"B077TLGP58",
"price":"13.99",
"email":"test#gmail.com"
}
]
So I am trying to run a for loop which will test whether all the form data already exists as a JSON object. Here's what I currently have:
// Check to see if it's already in asinJSON.json
for(i=0; i<asinJSON.length;i++){
if(asinJSON[i].email == email){
// Email is already in json
if(asinJSON[i].ASIN == inputVal){
// Email && ASIN are already in json
if(asinJSON[i].price == desiredPrice){
// Email, ASIN, Price all match. Duplicate.
console.log('same price found. product already exists.');
break;
}
// If price doesn't match, user wants to update price
console.log('updating price');
// Update price here
// updateJSON();
break;
}
// Existing user wants to add new product.
console.log('product not found');
// Insert product for existing user
// createAndAdd();
break;
}
// New user wants to add a product.
console.log('email not found.');
// insert product for new user
// createAndAdd();
break;
}
How it is now, when trying to test whether it can find the second object, it console.logs "product not found," which I understand is because it passes the first if statement but fails the second with the 1st object in the JSON array.
I'm also assuming it has to do with my break statements, and that something is wrong there. I've also tried return statents and haven't been able to figure it out. I've been self-taught so there are, unfortunately, some things that I have definitely missed along the way. But, I have looked aroung Google and StackOverflow and haven't really been able to find an answer, so here I am.
I'm ready to be schooled in how this logic should be set up to get it to work properly. I appreciate all the feedback in advance!
Use the find() method to search for a matching element.
if (asinJSON.find(({ASIN, price, email: json_email}) =>
ASIN == inputVal && price == desiredPrice && json_email == email)) {
console.log("product already exists");
} else {
console.log("product not found");
}
There are many options, one easy one is to use lodash
const email = <email to find>
const price = <price to find> (however, keep your mind around floating points comparison here...)
const ASIN = < ASIN to find >
if (findIndex(asinJSON, { ASIN, price, email }) > -1) {
// found
}
Is there something that I'm missing that would allow item to log as an object with a parameter, but when I try to access that parameter, it's undefined?
What I've tried so far:
console.log(item) => { title: "foo", content: "bar" } , that's fine
console.log(typeof item) => object
console.log(item.title) => "undefined"
I'll include some of the context just in case it's relevant to the problem.
var TextController = function(myCollection) {
this.myCollection = myCollection
}
TextController.prototype.list = function(req, res, next) {
this.myCollection.find({}).exec(function(err, doc) {
var set = new Set([])
doc.forEach(function(item) {
console.log(item) // Here item shows the parameter
console.log(item.title) // "undefined"
set.add(item.title)
})
res.json(set.get());
})
}
Based on suggestion I dropped debugger before this line to check what item actually is via the node repl debugger. This is what I found : http://hastebin.com/qatireweni.sm
From this I tried console.log(item._doc.title) and it works just fine.. So, this seems more like a mongoose question now than anything.
There are questions similar to this, but they seem to be related to 'this' accessing of objects or they're trying to get the object outside the scope of the function. In this case, I don't think I'm doing either of those, but inform me if I'm wrong. Thanks
Solution
You can call the toObject method in order to access the fields. For example:
var itemObject = item.toObject();
console.log(itemObject.title); // "foo"
Why
As you point out that the real fields are stored in the _doc field of the document.
But why console.log(item) => { title: "foo", content: "bar" }?
From the source code of mongoose(document.js), we can find that the toString method of Document call the toObject method. So console.log will show fields 'correctly'. The source code is shown below:
var inspect = require('util').inspect;
...
/**
* Helper for console.log
*
* #api public
*/
Document.prototype.inspect = function(options) {
var isPOJO = options &&
utils.getFunctionName(options.constructor) === 'Object';
var opts;
if (isPOJO) {
opts = options;
} else if (this.schema.options.toObject) {
opts = clone(this.schema.options.toObject);
} else {
opts = {};
}
opts.minimize = false;
opts.retainKeyOrder = true;
return this.toObject(opts);
};
/**
* Helper for console.log
*
* #api public
* #method toString
*/
Document.prototype.toString = function() {
return inspect(this.inspect());
};
Make sure that you have defined title in your schema:
var MyCollectionSchema = new mongoose.Schema({
_id: String,
title: String
});
Try performing a for in loop over item and see if you can access values.
for (var k in item) {
console.log(item[k]);
}
If it works, it would mean your keys have some non-printable characters or something like this.
From what you said in the comments, it looks like somehow item is an instance of a String primitive wrapper.
E.g.
var s = new String('test');
typeof s; //object
s instanceof String; //true
To verify this theory, try this:
eval('(' + item + ')').title;
It could also be that item is an object that has a toString method that displays what you see.
EDIT: To identify these issues quickly, you can use console.dir instead of console.log, since it display an interactive list of the object properties. You can also but a breakpoint and add a watch.
Use findOne() instead of find().
The find() method returns an array of values, even if you have only one possible result, you'll need to use item[0] to get it.
The findOne method returns one object or none, then you'll be able to access its properties with no issues.
Old question, but since I had a problem with this too, I'll answer it.
This probably happened because you're using find() instead of findOne(). So in the end, you're calling a method for an array of documents instead of a document, resulting in finding an array and not a single document. Using findOne() will let you get access the object normally.
A better way to tackle an issue like this is using doc.toObject() like this
doc.toObject({ getters: true })
other options include:
getters: apply all getters (path and virtual getters)
virtuals: apply virtual getters (can override getters option)
minimize: remove empty objects (defaults to true)
transform: a transform function to apply to the resulting document before returning
depopulate: depopulate any populated paths, replacing them with their original refs (defaults to false)
versionKey: whether to include the version key (defaults to true)
so for example you can say
Model.findOne().exec((err, doc) => {
if (!err) {
doc.toObject({ getters: true })
console.log('doc _id:', doc._id) // or title
}
})
and now it will work
You don't have whitespace or funny characters in ' title', do you? They can be defined if you've quoted identifiers into the object/map definition. For example:
var problem = {
' title': 'Foo',
'content': 'Bar'
};
That might cause console.log(item) to display similar to what you're expecting, but cause your undefined problem when you access the title property without it's preceding space.
I think using 'find' method returns an array of Documents.I tried this and I was able to print the title
for (var i = 0; i < doc.length; i++) {
console.log("iteration " + i);
console.log('ID:' + docs[i]._id);
console.log(docs[i].title);
}
If you only want to get the info without all mongoose benefits, save i.e., you can use .lean() in your query. It will get your info quicker and you'll can use it as an object directly.
https://mongoosejs.com/docs/api.html#query_Query-lean
As says in docs, this is the best to read-only scenarios.
Are you initializing your object?
function MyObject()
{
this.Title = "";
this.Content = "";
}
var myo1 = new MyObject();
If you do not initialize or have not set a title. You will get undefined.
When you make tue query, use .lean() E.g
const order = await Order.findId("84578437").lean()
find returns an array of object , so to access element use indexing, like
doc[0].title
How to perform case-insensitve lookup in javascript's set?
I have a situation where I have a set of allowed strings which doesn't ensure what case they would be in. I need to validate a user input against that set. How can I achieve this?
const countries = new Set();
countries.add("USA");
countries.add("japan");
// returns false, but is there any way I could get
//`my set to ignore case and return true?`
console.log(countries.has("usa"));
console.log(countries.has("USA"));
Just always call .toLowerCase on the string before you add it or before performing a .has check. For sure you can also abstract that into a class (if thats really necessary):
class CaseInsensitiveSet extends Set {
constructor(values) {
super(Array.from(values, it => it.toLowerCase()));
}
add(str) {
return super.add(str.toLowerCase());
}
has(str) {
return super.has(str.toLowerCase());
}
delete(str) {
return super.delete(str.toLowerCase());
}
}
const countries = new CaseInsensitiveSet([
"Usa",
]);
console.log(countries.has("usa")); // true
The short answer is "no". has uses SameValueZero algorithm to seek for a value's existence. See the comparison table here.
If performance is not a concern, you can try two searches, one with uppercased value, and one with lowercased value, and decide whether the value actually exists.
And the better approach would be to always insert the values by converting them to uppercase/lowercase and match accordingly for existence.
Sets check the exact data you have provided. The simplest solution is to save the data in lowercase or UPPERCASE and then search over the set using the .toLoserCase() String method.
Example:
// Save data in lowecase
const set1 = new Set(['test', 'other']);
console.log(set1.has('Test'));
// expected output: false
console.log(set1.has('Other'.toLowerCase()));
// expected output: false
You can add a hasIgnoreCase() prototype on Set.
Set.prototype.hasIgnoreCase = function(str) {
return this.has(str) || this.has(str.toUpperCase());
}
const countries = new Set();
countries.add("USA");
countries.add("japan");
// returns false, but is there any way I could get
//`my set to ignore case and return true?`
console.log(countries.hasIgnoreCase("usa"));
console.log(countries.hasIgnoreCase("USA"));
I'm trying to update/delete a fields in a Firestore document, but the fields that have a "period" in the name seem to be silently failing when trying to update/delete them. The reason I have periods is that I'm using URLs as the keys in the object, I feel this is a semi-common use case.
Example:
First create the document (this works fine)
db.collection("data").doc("temp").set({
helloworld: {
key1: 'foo'
},
hello.world: {
key1: 'bar'
}
})
If you try to delete the element without the period, it works fine.
db.collection("data").doc("temp").update({
helloworld: firebase.firestore.FieldValue.delete()
})
// Value is Deleted
If you try to delete the element with the period, it doesn't do anything.
db.collection("data").doc("temp").update({
hello.world: firebase.firestore.FieldValue.delete()
})
// Nothing Happens!
I've also tried
let u = {}
u['hello.world'] = firebase.firestore.FieldValue.delete()
db.collection("data").doc("temp").update(u)
// Nothing Happens!
Is this a bug? Are periods in field names supported? It seems strange I can create the element but not delete it.
The update operation is reading hello.world as a dot-separated path to a field called word that is nested like this:
{
hello: {
world: "Some value"
}
}
If you have a field with a dot in the name you need to use FieldPath to refer to it literally in an update:
https://firebase.google.com/docs/reference/js/firebase.firestore.FieldPath
So this is what you want:
doc.update(
firebase.firestore.FieldPath("hello.world"),
firebase.firestore.FieldValue.delete());
You need to wrap it in quotes when you use periods in the name on an update or delete like:
db.collection("data").doc("temp").update({
"hello.world": firebase.firestore.FieldValue.delete()
})
or for dynamic names:
[`hello.${world}`]: firebase.firestore.FieldValue.delete()
I found a workaround if you are using dynamic keys and J Livengood's solution doesn't work for you. You can use the "set" method with "merge: true" to selectively set the key with the delete value.
var dynamicKey = "hello.world"
// ES6
db.collection("data").doc("temp").set({
[dynamicKey]: firebase.firestore.FieldValue.delete()
}, { merge: true })
// ES5
var obj = {}
obj[dynamicKey] = firebase.firestore.FieldValue.delete()
db.collection("data").doc("temp").set(obj, { merge: true })
None of the other answers worked for me, the closest one had a new() keyword missing, here is what worked for me
let fpath = new firestore.firestore.FieldPath(`hello.${world}`);
doc.update(
fpath,
firestore.firestore.FieldValue.delete()
);
I've done some research on this issue. I am trying to manipulate an array of calculated values that looks like this in the console:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:Complex {re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
8:Complex { re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
This array is created dynamically through some math that I've come up with so there is no input data that I can give you. I'm trying to make the above array look like this:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:40.38334500994142
8:39.55961661806138
Using mathjs, I was able to evaluate my expressions and dynamically add the values into an array with the array.push command and display them. However, my code breaks once the imaginary values pop up in the results of my array.
How can I remove these imaginary numbers from my array? In other words, I need to remove the "im:" parts of the values when they begin to appear before I push them to the displayed array.
I tried to do this with some code I found from a previous answer to someone else's question (How do I remove a particular element from an array in JavaScript?) splice command like this:
var nodeVoltage2 = parser.eval(expression2);
//checks if there are imaginary values and removes them
if ("im" in nodeVoltage2) {
nodeVoltage2.splice(2,1)
}
//adds value to result array for analysis
nodeVoltages.push(nodeVoltage2);
but it returns in the console that "im is not defined".
Any help is greatly appreciated!
You can use the array map function.
Basically, we loop through the array. If the item has a .re property, we take that value only. If there is no .re property, we keep the value as is.
We can either write that in shorthand, as with result using the ternary operator and arrow function, or we can write it in a slightly more verbose but traditional way, as with resultTwo
let data = [
48
,47.71306060387108
,47.250273223993105
,46.59686907269243
,45.71876416434013
,44.53304242029258
,42.745236969423615
,{re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
,{ re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
]
let result = data.map((x) => x && x.re ? x.re : x);
let resultTwo = data.map(function(elem) {
// First, we need to check that the array element is not null / undefined
// We then need to check that it has a property called re that is also not null / undefined
if (elem != null && elem.re != null) {
// Just return the property we're interested in
return elem.re;
} else {
// Return the element as is
return elem;
}
});
console.log(result);
console.log(resultTwo);