Updating pointers within Mongoose Objects - javascript

Hi so I am working on a project using MongoDB and Mongoose.
I have a scheme where I check if a certain attribute exists for a given Mongoose object; if it doesn't I create a new one with a pointer; if there exists one I merely get a pointer to it.
Now I update the contents of these pointers, and I attempt to .save() the Mongoose object. However it does not update. I've used console logs and it tells me that the pointers have changed but not the actual contents inside the Mongoose objects. Has anyone else come by this problem? Is there any way around this? Does it matter the order I do it (as in if I push data into an attribute of the object then I modify the contents of the pointer or visa-versa)?
I also thought about how pointers get affected by pushing into arrays, but if I remember correctly java shallow copies content into arrays. So the pointers should still point to the same object?
Thanks
Model.findOne({ name: personA.name }, function(err, model) {
// if such an object exists dbModel points to it otherwise create new object
var dbModel;
if(model) dbModel = model;
else dbModel = new Model({
name: personA.name,
hobbies: []
});
var newHobby;
// helper function returns index of object in the array with sports = basketball
// if no such object exists returns -1
hobbyIdx = indexOfWithAttr(dbModel.hobbies, "sports", "basketball");
if(hobbyIdx == -1) {
newHobby = {
sports: basketball,
gears: []
}
dbModel.hobbies.push(newHobby);
}
else { newHobby = dbModels.hobbies[hobbyIdx]; }
// code changing contents of newHobby goes here...
newHobby.gears.push("sneakers");
// then finally save...
dbModel.save();
}
then the output is
//prints '{ sports: basketball }'
console.log(newHobby);
// prints '{ name: John, hobbies: [{ sports: basketball }] }'
console.log(dbModel);

Related

Clone and update in groovy

In javascript there is an easy way to generate cloned object with some of the fields updated:
const person = {
isHuman: false,
name: "gabe"
};
const person2 = {
...person1,
name: 'alice'
}
Is there a way to do something like in groovy without copying all the fields manually? I am writing testcases where I wanna generate data with one attribute changed at a time.
Can you use #Immutable(copyWith = true)
#Immutable(copyWith = true)
class Person {
String first, last
}
def tim = new Person('tim', 'yates')
def alice = tim.copyWith(first:'alice')
assert tim.first == 'tim'
assert alice.first == 'alice'
https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/ImmutableBase.html#copyWith
There are many ways this can be done.
One is to construct instances by spreading in a map, e.g., given:
class Person { String name; Boolean isHuman; }
An instance can be constructed using the same spread-map operator I linked to:
m1 = [ name: "Gabe", isHuman: true ]
p1 = new Person(*:m1)
println p1
// Person: Gabe, isHuman=true
This avoids actual work. An exception will be thrown if a map key isn't an instance property.
A utility method grabbing (non-synthetic) prop names from a class, and iterates while putting the name/value pairs into a map is also an option (and affords a bit more safety):
def toMap(obj) {
obj.class.declaredFields
.findAll { !it.synthetic }
.collectEntries { [(it.name): obj."$it.name" ] }
}
Now we can construct a "prototype" object, but override properties:
p2 = new Person(*:toMap(p1), name: "Alice")
println p2
// Person: Alice, isHuman=true
There are also libraries that do this type of work.
Depending on your actual usecase it may not be necessary to do anything other than passing a map, however (duck typing).

Delete property from shallow copied object

If I have one object, and shallow copy of it. For example:
var person = {
name: "Foo",
age: 10,
child: {
name: "Matrix"
}
}
var copiedPerson = {...person}
console.log(person, copiedPerson);
If I change person.name = "NewName";, copedPerson will stay intact.
If I change person.age = 8;, copiedPerson will stay intact.
But if I change person.child.name = "Neo";, copiedPerson.name will also through reference to point also to same name "Neo".
Everything about that is clear to me.
But I do not understand, why when I delete person.child;, nothing happens to copiedPerson.child;
In my logic cause both of them changes when I change one of them, now I also expected when one of them is deleted that other one should also be deleted. (Cause they references to same location in memory)
Can someone explain me why this didn't happen and which part I misunderstood?
There is a little gap in the mental model you're having about the references right now. So essentially, you understand that if you change the nested object person.child.name the value in the copiedPerson.child.name would change too.
But at the end of the day, the child property is only containing the reference of the nested object for both person and the copiedPerson objects.
So, when you delete it from the original person object, you're deleting the reference of this nested object from the person's child property but this nested object still remains in the memory
Hence, the reference contained in the copiedPerson.child still remains untouched and can access this object saved in the memory
delete does not destroy the object that is referenced by a variable or property.
delete removes a property from an object - in your case the person object - just like an assignment adds it.
it is cause the different variables specify on the same object. You should clone obj by cloneObj function
function cloneObj(obj) {
var res = {};
for (var i in obj) {
if (typeof obj[i] == "object") {
res[i] = cloneObj(obj[i]);
} else {
res[i] = obj[i];
}
}
return res;
}
var person = {
name: "Foo",
age: 10,
child: {
name: "Matrix"
}
}
var copiedPerson = cloneObj(person);
copiedPerson.child.name = "Neo";
console.log(person);
console.log(copiedPerson);

Duplication of items in a Javascript Set

I was going through basics of Javscript Set.According to its defintion, A Set is a special type collection – “set of values” (without keys), where each value may occur only once.
But I see when it comes to reference types the behavior is different. Consider the following snippet:
let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
console.log("Scenario 1");
for (let user of set) {
console.log(user.name);
}
let set1 = new Set();
set1.add({ name: "John" });
set1.add({ name: "Pete" });
set1.add({ name: "Mary" });
set1.add({ name: "John" });
console.log("Scenario 2");
for (let user of set1) {
console.log(user.name);
}
I see in the scenario 1, it wont allow duplicates to be added as they are the same references. But in scenario 2 I see duplicates are being added.
Can some explain this behavior? Or Am I missing something.
How scenario 1 is different from 2?
Try doing a check of {name: 'John'} === {name: 'John'}. You would find it returns false.
Every new object has a different reference even though the contents can be same. If it gives false to you, the Set would consider it a different element too.
When you assign a variable with a Reference value, its memory location gets copied.
For example:
let john = {name: 'John'} // lets say memory: XYZ
So, every time when you do: set.add(john);, you are adding the memory location in the set. So, the Set would see you adding XYZ everytime and it won't accept duplicates.
In the second case,
When you do:
`set1.add({ name: "John" });` // You added maybe XYF
`set1.add({ name: "John" });` // You added maybe XYN
So, your Set treats them differently and adds both of them.
A Set does not look at the contents of the object itself. It only looks at the pointer to the object.
If it's not a pointer to the same physical object, then it's allowed to be added to the Set as a different physical object. In fact, you can add an object to the set and then change it's contents afterwards because the fact that it's in the set has NOTHING to do with the contents of the object, only the physical pointer to the object. If it's not the same pointer to the same object, then it can be added separately.
Here's an example:
let s = new Set();
let x1 = {name: "John"};
let x2 = {name: "John"};
console.log(x1 === x2); // false, not the same physical object
s.add(x1);
console.log(s.has(x1)); // true
console.log(s.has(x2)); // false
s.add(x2);
console.log(s.has(x2)); // true
console.log(Array.from(s)); // [{name: "John"}, {name: "John"}];
// now modify x1
x1.name = "Bob";
// the x1 object is still in the set, even though you modified it
// because being in the set has NOTHING to do with the contents of the object at all
console.log(s.has(x1)); // true
console.log(Array.from(s)); // [{name: "Bob"}, {name: "John"}];

Objection.js not proper return

i am not getting proper the return after insertgraph in objection.js
i am getting the result like :
[
User {
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: UserRoles { role_id: 2, user_id: 37 },
id: 37
}
]
where i want the result like :
[
{
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: { role_id: 2, user_id: 37 },
id: 37
}
]
There are few ways to get rid of the specific class references:
1. JSON.parse(JSON.stringify(result))
This will rebuild the object by first converting the whole object to a string (in JSON format), and then by doing the reverse -- creating a new object from a string. As this string format (JSON) does not store custom class information, it achieves your purpose. However, if your object has functions, symbols, then these will be omitted. Also Map and Set will become empty objects. For a more complete list of restrictions. See JSON.stringify
2. Deep Clone
There are several deep-clone functions out there, that may or may not do what you expect. Some will still try to maintain the original prototype references, so that it would not benefit you. You can find some here: How to Deep clone in javascript. For your case, this one would do the job:
function deepClone(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj; // primitives
if (hash.has(obj)) return hash.get(obj); // cyclic reference
const result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);
return Object.assign(result, ...Object.keys(obj).map(
key => ({ [key]: deepClone(obj[key], hash) }) ));
}
You call it as newResult = deepClone(result).
The advantage here, is that it supports cyclic references, which JSON.stringify cannot handle. Also, there is no string conversion happening, which really is not necessary. You can extend this function to keep deal with some class instances that you like to stay that way. See how you can support Date, RegExp, Map, Set, ... in this answer. But don't do the "catch-all" line.
3. Change the prototype
With this strategy you mutate the result in-place.
function removeClasses(obj, hash = new WeakSet()) {
if (Object(obj) !== obj) return; // primitives
if (hash.has(obj)) return; // cyclic reference
hash.add(obj);
if (Array.isArray(obj)) Object.setPrototypeOf(obj, Array.prototype);
else Object.setPrototypeOf(obj, Object.prototype);
for (let value of Object.values(obj)) {
removeClasses(value, hash);
}
}
Call it as removeClasses(result), and afterwards result will have been "fixed". Again, this method does not use a conversion to string. As it does not create a new object either, it consumes less memory. But on the other hand you mutate an object, and some would advise against that.

QML Javascript Dictionary of Property Alias not Updating

My question is the following:
Do changes to the javascript dictionary values not modify the actual value that is mapped, but rather its own internal copy? Is there a way to get around this?
I have a javascript dictionary that contains property aliases of an object.
When I assign them values, the objects in the dictionary itself changes but it does not propagate outward to the actual display that I want to change.
I have had this problem before, placing the dot access outside of the dictionary access fixed it. However, I cannot do it this time around due to the fact that you cannot dot access using .text because it produces error of cannot read property of undefined.
QML: Cannot read property 'xxx' of undefined
My code resembles something of the following example, I had it obscured to protect actual info so sorry if it is a cringy example.
onUpdate passes in another dictionary that I want to tie to the local .qml dictionary.
ControllerDisplay.qml
// ...
property alias id1: id_box.text
// ...
SomeBox
{
id: id_box
text: "some text"
}
main.qml
ControllerDisplay{
id: controller
}
// ...
Connections
{
target: myguimodel
onUpdate:
{
var dict = { "ID1" : controller.id1}
for (var key in updates)
{
dict[key] = updates[key] // does NOT change the value in ControllerDisplay
controller.id1 = updates[key] // DOES change the value ControllerDisplay
}
}
}
When you do var dict = { "ID1" : controller.id1}, you store the value of controller.id1, not a reference to it.
If you want to be able to modify it you could do:
var dict = { "ID1": { "object": controller, "property": "id1"}};
for (var key in updates) {
var target = dict[key];
target.object[target.property] = updates[key];
}
This whole code doesn't look really QML idiomatic though. I would try using property binding if I were you.

Categories

Resources