So while trying to update a document in mongoose, I realized that when I do obj.key=value to a document I obtained with Model.findOne(), it doesn'st assign the property to its value. But after trying obj.set(key, value), the property is assigned to its value in the document. So why is that? Usually when i do the first method to an object, the object gets the property. What is the .set() function? Does it have something to do with mongoose?
//this works
async function updateItem(){
let updatedItem = await Item.findOne({name:req.body.itemName});
Object.entries(req.body).forEach(elem=>{
if(elem[0]!=="itemName"){
updatedItem.set(elem[0], elem[1]);
};
});
};
updateItem();
});
//this doesn't work
async function updateItem(){
let updatedItem = await Item.findOne({name:req.body.itemName});
Object.entries(req.body).forEach(elem=>{
if(elem[0]!=="itemName"){
updatedItem.elem[0] = elem[1];
};
});
};
updateItem();
});
It means that updatedItem is not an object, it's a Map, and to add items to a Map you need to use the get method.
Another thing to point out is that when you set updatedItem.elem[0], you're literally trying to add the key "elem[0]" to updatedItem. To fix this, you need to use dynamic property notation with square brackets:
updatedItem[elem[0]] = elem[1];
This makes a new key with the value of elem[0], instead of the key being elem[0].
Related
I am following a course on blockchain which has the following piece of code.
What does " index:this.chain.length+1 " mean? Is index a variable in the object newBlock? Or is it a key value pair? If it is a variable, why don't we simply use index=this.chain.length+1? Also what is the type of the object newBlock?
function Blockchain()
{
this.chain=[];
this.newTranscations=[];
}
Blockchain.prototype.createNeBlock = function(nonce,previousBlockHash,hash)
{
const newBlock ={
index:this.chain.length+1,
timestamp:Date.now(),
// all of the transactions in this block will be the transactions that waiting to be put in a block
transactions:this.newTranscations,
// nonce is hust a number giving proof of the transaction
nonce:nonce,
hash:hash,
previousBlockHash: previousBlockHash
}
// As we move all the pending transactions to the new block, we clear this array
this.newTranscations=[];
this.chain.push(newBlock);
return newBlock;
}
var Box = {
"playdoh":{"playdoh":["none", "some", "none", "none", "some"]}
};
Box of playdoh upon playdoh, you're getting into the study of Objects/Arrays/Maps.
To call the above out, it'd be
console.log(Box["playdoh"]["playdoh"][0]);
= none
console.log(Box["playdoh"]["playdoh"][4]);
= some
console.log(Box["playdoh"]["playdoh"][5]);
= null (undefined)
is the same as
console.log(Box.playdoh.playdoh[0]);
= none
console.log(Box.playdoh.playdoh[4]);
= some
console.log(Box.playdoh.playdoh[5]);
= null (undefined)
It is one of several ways to initialize an object called newBlock in javascript. Take a look at this documentation on MDN
The index property is of type number in this case, and it is set to equal chain[].length + 1
getCoinPrice(coinName: string) {
return this._http
.get(
`https://min-api.cryptocompare.com/data/pricemulti?fsyms=${coinName}&tsyms=EUR`
).pipe(map((result) => (result)));
JSON from the link with "BTC" as coinName is: {"BTC":{"EUR":8226.43}} and the method gives me back an observable.
How would I return the price value(8226.43) in a variable?
Try this code. Should just work fine for you.
getCoinPrice(coinName: string) {
return this._http
.get(
`https://min-api.cryptocompare.com/data/pricemulti?fsyms=${coinName}&tsyms=EUR`
).pipe(map((result) => (result.BTC.EUR)));
You can learn more about how to access objects and their value here https://www.w3schools.com/js/js_objects.asp
Here is the Javascript MDN explanation about how to work with objects: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
Working example:
This is to show how we will get the value you desired by accessing the objects with .
//Your results
var result = JSON.parse('{"BTC":{"EUR":8226.43}}');
//This will print out 8226.43
console.log(result.BTC.EUR)
You want result[coinName]["EUR"]
As per observable result you are getting {"BTC":{"EUR":8226.43}} for coinName BTC, you want to retrieve "8226.43" from it.
So,
coinName = 'BTC' & observableResult = {"BTC":{"EUR":8226.43}}
If you want to get the value based on coinName, you could use the below method since coinName is also the key (BTC) in the observableResult object.
observableResult[coinName] // This will result to {EUR: 8226.43}
So, observableResult[coinName].EUR will result to 8226.43
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
I'm playing around with a Node server and having trouble setting values in Firebase with a provided String.
The issue: When I try to set the value of the carId variable in the first line of the for loop, it is set as carId: true rather than the expected behavior --> exampleCardId12345: true.
Why is the value being set to carId rather than the value of the carId variable, which I set prior to the for loop?
db.ref('/cars').once("value", function(snapshot) {
snapshot.forEach(function(data) {
var carId = data.key;
var drivers = data.val().drivers;
for(key in drivers) {
db.ref('/carsById/'+key).set({carId: true});
}
});
});
If you want to use a variable's value for a key, use the computed property name syntax:
db.ref('/carsById/'+key).set({ [carId]: true });
^ ^
^ ^
I want to store as the following method, and get the constant value, by querying using key to find value or by value to find the key
function my_reference() {
return {
30:'',
31:'ERR591',
32:'ERR761',
33:'ERR671',
34:'ERR551',
};
}
console.log( my_reference[31],
my_reference.31,
my_reference().31,
my_reference()[31]
);
my_reference[31],
Trying to read a property (which doesn't exist) of a function. The property is on the object that is the return value of calling the function.
my_reference.31,
Trying to use a number as an identifier. This isn't allowed.
my_reference().31,
Trying to use a number as an identifier. This isn't allowed.
my_reference()[31]
This works
You need to execute the function with my_reference() and after that access the property you want to.. but the keys in javascript objects are always strings:
console.log(my_reference()['31']);
You don't need to use a function to store the references:
var reference = {
30:'',
31:'ERR591',
32:'ERR761',
33:'ERR671',
34:''
};
console.log(reference[31]);
You have to call function if you want it to return result, function called by :
my_reference()
So the both first lines will not work because my_reference will return the function it self and not call it :
my_reference[31]
my_reference.31
The third also will not work console.log(my_reference().31); because attribute can't be numeric.
Hope this helps.
Here is the fixed code
function my_reference() {
return {
_30:'',
_31:'ERR591',
_32:'ERR761',
_33:'ERR671',
_34:'ERR551'
};
}
var f = my_reference();
console.log(f["_31"]);
console.log(f._31);
console.log(my_reference()._31);
console.log(my_reference()["_31"]);
Variables can't be named with just numbers
The first two should be the returned object