I am using mongoDB to store the document. In my http get request i pull the particular document record and save it request object to process on it(using middlewear). Later when there is any patch/put request come then i use the same request object and modify the paramater. But problem lies when i want to use the previous request stored values after modifying in put/patch request. Even i tried to store in different variable under request parameter, but when i change anything on req values, all request values get modified. Below is chuck of code.
req.PreviousStoreData = _.head(data); //data object
req.currentData = _.head(data); // copy data object
req.currentData.status = req.body.status;
// now if try to see the PreviousStoreData then it also got modified with latest status (modified only in currentData param)
If anything not understood well, please ping me back
Use Object.assign(), like that:
req.PreviousStoreData = {};
Object.assign(req.PreviousStoreData, _.head(data));
req.currentData = _.head(data);
req.currentData.status = req.body.status;
By typing "=" you set a reference to an object, which is the same object that currentData uses. Changing this object will cause both values to change.
Object.assign() copies all parameters from a source object (last argument) to the destination objects (not-last arguments), so you're actually duplicating an object instead of referring to it.
Object.assign() does seem to be the way to go. But the first parameter needs to be an empty object, to be the source object so that you dont affect the reference.
req.PreviousStoreData = Object.assign({}, _.head(data));
req.currentData = Object.assign({}, _.head(data));
req.currentData.status = req.body.status;
Here you are duplicating the Object, rather than assigning it the reference.
Related
In the Google Getting started with Node.js tutorial they perform the following operation
data = {...data};
in the code for sending data to Firestore.
You can see it on their Github, line 63.
As far as I can tell this doesn't do anything.
Is there a good reason for doing this?
Is it potentially future proofing, so that if you added your own data you'd be less likely to do something like data = {data, moreData}?
#Manu's answer details what the line of code is doing, but not why it's there.
I don't know exactly why the Google code example uses this approach, but I would guess at the following reason (and would do the same myself in this situation):
Because objects in JavaScript are passed by reference, it becomes necessary to rebuild the 'data' object from it's constituent parts to avoid the original data object being further modified by the ref.set(data) call on line 64 of the example code:
await ref.set(data);
For example, in MongoDB, when you pass an object into a write or update method, Mongo will actually modify the object to add extra properties such as the datetime it was insert into a collection or it's ID within the collection. I don't know for sure if Firestore does the same, but if it doesn't now, it's possible that it may in future. If it does, and if your original code that calls the update method from Google's example code goes on to further manipulate the data object that it originally passed, that object would now have extra properties on it that may cause unexpected problems. Therefore, it's prudent to rebuild the data object from the original object's properties to avoid contamination of the original object elsewhere in code.
I hope that makes sense - the more I think about it, the more I'm convinced that this must be the reason and it's actually a great learning point.
I include the full original function from Google's code here in case others come across this in future, since the code is subject to change (copied from https://github.com/GoogleCloudPlatform/nodejs-getting-started/blob/master/bookshelf/books/firestore.js at the time of writing this answer):
// Creates a new book or updates an existing book with new data.
async function update(id, data) {
let ref;
if (id === null) {
ref = db.collection(collection).doc();
} else {
ref = db.collection(collection).doc(id);
}
data.id = ref.id;
data = {...data};
await ref.set(data);
return data;
}
It's making a shallow copy of data; let's say you have a third-party function that mutates the input:
const foo = input => {
input['changed'] = true;
}
And you need to call it, but don't want to get your object modified, so instead of:
data = {life: 42}
foo(data)
// > data
// { life: 42, changed: true }
You may use the Spread Syntax:
data = {life: 42}
foo({...data})
// > data
// { life: 42 }
Not sure if this is the particular case with Firestone but the thing is: spreading an object you get a shallow copy of that obj.
===
Related: Object copy using Spread operator actually shallow or deep?
What is wrong with this query?
const db = firebase.firestore()
const query = db.doc(this.props.user.uid).collection('statements').orderBy('uploadedOn', 'desc').limit(50)
I get the following error:
Uncaught Error: Invalid document reference. Document references must have an even number of segments, but FrMd6Wqch8XJm32HihF14tl6Wui2 has 1
at new FirestoreError (index.cjs.js:346)
at Function.DocumentReference.forPath (index.cjs.js:15563)
at Firestore.doc (index.cjs.js:15368)
at UploadStatementPresentation.componentWillMount (UploadStatementPage.jsx:61)
at UploadStatementPresentation.componentWillMount (createPrototypeProxy.js:44)
at callComponentWillMount (react-dom.development.js:6872)
at mountClassInstance (react-dom.development.js:6968)
at updateClassComponent (react-dom.development.js:8337)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)
Since you haven't described what exactly you're trying to query, I'll just point out that all documents must be in a collection, without exception. So, if you say this:
db.doc(this.props.user.uid)
Firestore assumes that the string you're passing to doc() contains both the collection and document id separated by a slash. But this seems to be highly unlikely in your case. You need to determine which collection the uid is in, and use that first when you build the reference to the collection you want to query. Assuming that you do have a statements subcollection in the uid document, and that some other collection contains the uid document, you'll have to specify the full path like this:
db.collection('that-other-collection').doc(this.props.user.uid).collection('statements')
Of course, only you know the actual structure of your data.
If you want to get a collection of documents with querying, you don’t have to specify a document id. Below code should work in this case.
const query = db.collection('statements').orderBy('uploadedOn', 'desc').limit(50)
Or if you want to get the document, you can pass the document id to doc() method. In that case, the code should be.
const query = db.collection('statements').doc(this.props.user.uid)
For more details about querying firestorm data: https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0
For others having this issue, make sure that no document reference has an empty string.
I had this issue when using a get method with uid input as below and forgot to check if uid is empty
private fun getFullRef(uid: String): CollectionReference {
return ref.document(uid).collection(FireContact.SUB_PATH)
}
I want to generate the short id of number type, but when I call shortid method and output id and emaill, the contents of the output in the console are the same as the incoming variable. the gist in github
I get an answer that change 'var self = this ' to 'var self = {}', because 'this' in method equal 'global'.
Why does this code snippet not write the values back to Excel unless I un-comment the range.values=range.values line?
$('#run').click(function() {
invokeRun()
.catch(OfficeHelpers.logError);
});
function invokeRun() {
return Excel.run(function(context) {
var range = context.workbook.worksheets.getItem("Sheet1").getRange("A1:B3");
range.load('values');
return context.sync()
.then(function() {
range.values[1][1]=99;
console.log(JSON.stringify(range.values));
//range.values=range.values
return context.sync();
});
});
}
Array properties are special. I have added a page on my website to describe the topic: Reading and writing array properties.
Summarizing from there, the way that the proxy-object model works, whenever you set a property on an object, the Office.js runtime has a hook into the setter and getter, which is used to intercept the call and add the command to the queue.
Let's take an example of a regular property first. Per the above, whenever you set something like range.format.fill.color = "red", the setter for the color property intercepts the request and internally adds a command into the queue to set the range fill color to red (to be dispatched with the next context.sync)
On the other hand, if all you had was var color = range.format.fill.color
(after a load and a sync, of course), the getter would fire instead of the setter, and the color variable would get the range's current fill color.
Now, that was regular properties. Whenever you set an element of the array, you are effectively accessing the array value as a getter. From a runtime perspective, this line is no different from a slightly more verbose version:
var array = range.values;
array[r][c] = '-';
Because the getter for range.values returns a perfectly plain JS array object, accessing it and then setting its value does nothing to propagate it back to the original Range object.
If you want the values to get reflected back, the best thing is to get a reference to the array right after the sync (i.e., var array = range.values, just as above), then set the values on the array as needed, and then finally set it back to the object: range.values = array.
It means you could also modify the values array in place, and then assign the values property back to itself at the completion of the loop (range.values = range.values). However, this looks awkward, as if it’s a no-op, whereas in reality it is not. So personally, I prefer to retrieve the array at the beginning and assign it to its own variable, then do any necessary modifications, and finally set the full array back.
UPDATE to clarify the above:
To be very clear, the arrays returned by accessing the .values, .formulas, etc., ARE pure vanilla JS arrays. That's actually the crux of the problem: that in order for Office.js to return pure objects, it means that those pure objects can't be "spiked" with the ability to reflect changes.
For what it's worth, we actually have an upcoming feature that should be rolling out in a month or two, where we will be introducing an object.set syntax, as in:
range.set({
values: [[1, 2], [3, 4]],
format: {
fill: {
color: "purple"
}
}
}
This will make it more convenient to set multiple properties on the same object, but it might also make the array properties easier to deal with.
I have started using NSIncrementalStore. When you process a fetch request, you first have to process the predicate to get your internal reference objects. Then you convert these to objectID's and then you ask the context to get the corresponding managedObjects. At least that is my interpretation of the available documentation.
let fetchedReferences : [Int] = Array(names.keys) //names represent my backingstore
var fetchedObjectIDs : [NSManagedObjectID] = []
for reference in fetchedReferences
{
fetchedObjectIDs.append(self.newObjectIDForEntity(request.entity, referenceObject: reference))
}
var fetchedObjects : [NSManagedObject] = []
for objectID in fetchedObjectIDs
{
fetchedObjects.append(context.objectWithID(objectID))
}
"newObjectIDForEntity" is also used to obtain permanent objectID's (see obtainPermanentIDsForObjects)
I want to know what "newObjectIDForEntity" does. Does it make a new instance for the same object or does it each time internally create a new object? What I mean is this: if I create a new managed object and then fetch the object, I will have called "newObjectIDForEntity" twice for the same object. Does core data now think there are 1 or 2 objects?
Does it make a new instance for the same object or does it each time internally create a new object?
newObjectIDForEntity:referenceObject: is one of two utility methods for mapping between the store's internal representation of a managed object snapshot and an NSManagedObjectID. It's inverse is referenceObjectForObjectID:. As you might guess from the name, newObjectIDForEntity:referenceObject: returns an object considered to have a retain count of 1. newObjectIDForEntity:referenceObject: calls an internal factory method for generating an NSManagedObjectID that is unique to that reference object in this persistent store. Once that has been done, referenceObjectForObjectID: can look up that NSManagedObjectID and return the reference object it represents.
What I mean is this: if I create a new managed object and then fetch the object, I will have called "newObjectIDForEntity" twice for the same object. Does core data now think there are 1 or 2 objects?
I assume you mean an NSManagedObjectContext that is using your store creates the managed object. You can call newObjectIDForEntity:referenceObject: as many times as you want, the NSManagedObjectID instance may be different, but the data it represents is unchanged. It will know that it points to the same reference object as an earlier call with the same reference data and entity description.