Javascript - How to update a document in couchdb? - javascript

So we need to be able to update JSON objects in cloudant using javascript. Our teacher told us something about using the _rev number but I've got no clue on how to begin.
Let's say that this is the document I need to update:
{
_id:"bla",
_rev:"blabla",
name:"something"
}
And I want to update it to this:
{
_id:"bla",
_rev:"blabla",
name:"something else"
}

Please see the following docs: http://guide.couchdb.org/editions/1/en/api.html#revisions
Basically you need to fetch the existing document, change the fields and post it back, making sure the revision is correct. Revision is used to prevent updates of documents that have been updated since you got your copy (conflict).

Related

Redux - Remove object from store on http response error

Consider the following flow:
I have a page with a list of "products" and a modal to create a single "product". I open the modal, fill the form and submit the form.
At this point, I dispatch an action CREATING_PRODUCT, add the product to the store and send the http request to the server.
I close the modal and display the list of results with the new product.
Let's suppose I receive an error response from the server.
Desired behavior:
I would like to display an error, remove the project from the list, re-open the modal and display the form already filled.
Question
How can I find that project and remove it the list? I don't have an id (or a combination of unique properties) to find that project in the store. I don't see a clean way to link a request/response to that "product" object in the store.
Possible solution
The client adds a "requestId" into the project before adding it to the store. On response error, I dispatch a generic "CREATE_ERROR" and I remove the project with that requestId from the store.
Extra
Same problem with edit and delete. For example during a delete should I keep a reference to the deleted project with the requestId in the store, until the http request is successful?
I bet it is a problem with a common solution, but I can't find examples.
Thanks!
In general, your Redux store should be modeled somewhat like a relational database, in that every time you have a list of data models, each element of the list should have its own identifier. This helps a lot when dealing with more complex data schemes.
You should probably store your projects as an object, something like:
{
// ...other store properties
projects: {
"_0": { // ... project properties }
"_1": { // ... project properties }
// ...more projects...
},
}
This way, whenever you need to mess with an existing project, you can just reference its id and use projects[id] to access that project. This would also solve the edit and delete cases, as you could just pass the IDs around as handles.
I like this short piece on why your Redux store should be mostly flat and why data should always have identifiers very much. It also talks about using selectors to "hide" your IDs away, which may or may not be useful for you.
In your case, as you are getting IDs from a server, you could have an ID prefix which indicates unsaved values. So your projects object would become something like:
projects: {
"_0": { // ... }
"_1": { // ... }
"UNSAVED_2": { // ... }
}
This way, you could easily identify unsaved values and handle them when an error occurs, still get the benefits of generating temp IDs on the client-side in order to revert changes on error, and also warn your user if they try to leave your app while their data still hasn't been synchronized - just check if there are any "UNSAVED" IDs :)
When you get a response from the server, you could change the "UNSAVED_suffix" ID to an actual ID.

Find all class and id names in an Ace Editor HTML script

What I'm trying to do:
Collect all the class and id names in an Ace Editor html script.
Right now my plan is to detect user changes (.on('change'...)) and get the current token using the cursor position. If the token is a not 'unquoted' 'attribute-value' type, I want to iterate back through previous tokens in order to find the 'attribute-name' type token to which that 'attribute-value' belongs and identify whether it is a class or id (I can't just detect the creation of an 'attribute-name' token because the user can go back and change the attribute-values later without changing the name, and I need to detect those changes).
I can do everything except for get previous tokens. I looked up some documentation and the TokenIterator is supposed to be able to do that, but when I try to do something like var iter = new TokeIterator(), my console says that TokenIterator is undefined. I've searched google over and over, but found no results. If the truth is out there I'm obviously not using the right words to find it, but they're the only words I've got.
Is some way built into Ace to iterate through tokens? I know I'm not seeing all the properties and methods on the editor instance object when I console log it, because I can use methods in my script that I can't see in that log. Is there one there that does what I want?
If not, how do I load the TokenIterator? I think something similar went on when I tried to use SnippetManager a while back and it turned out I actually had to do this to make it work:
var tillPageLoaded = setInterval(function() { // Makes sure page doesn't load forever on startup
if( document.readyState === 'complete') {
clearInterval(tillPageLoaded);
ace.config.loadModule('ace/ext/language_tools', function () {
editor.insertSnippet( myString );
});
}
}, 5);
Is this the same kind of situation? If so, what needs to be in .loadModules(...)? Do I need to reference a script somewhere? Does it need to be loaded some other way?
Is there built in functionality for Ace that would already do everything I want?
Other than that, if anyone has any better ideas of how to go about this with Ace, those would be very welcome.
you can get TokenIterator by using
var TokenIterator = ace.require("ace/token_iterator").TokenIterator
see https://github.com/ajaxorg/ace/blob/master/lib/ace/mode/folding/xml.js#L38 for an example of its usage.

get jquery.data() related to an element from a saved html using javascript or jquery

I have some html that I want to save in database for a later retrieve.
Let's imagine the html is a simple div
<div id="mydiv">This is my div</div>
I use jQuery.data() to store some information related to that div like this :
$("#mydiv").data("divNumber", "5").data("divRole", "adminMessage") .....
Then finally I save the html in database, but I would like to be able to get those information later when I need them :
var myHtml = { here I get the html from my database }
$("body").append(myHtml);
console.log( $("#mydiv").data("divNumber") ); // I want it to show 5
console.log( $("#mydiv").data("divRole") ); // I want it to show adminMessag
from my understanding of jquery.data() I think it will just store those data information temporary in an internal cache and if I save the html in the database, and I leave the page, they will be lost !!
So is there a way to keep those jquery.data() information and retrieve them whenever I want ? or maybe there is another "better" way to achieve the same thing (I am not looking for localStorage method)
You can convert the .data() to data attributes on the html and save that.
$("#mydiv").data("divNumber", "5").data("divRole", "adminMessage");
$.each($("#mydiv").data(), function(k,v){
$("#mydiv").attr("data-"+k.replace(/[A-Z]/g, "-$&"), v);
});
var toDatabase = $("#mydiv")[0].outerHTML;
//save to database
// ...
// retrieve from database
var fromDatabase = $(toDatabase);
$('body').append(fromDatabase.data('divNumber'));
$('body').append('<br>');
$('body').append(fromDatabase.data('divRole'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv">This is my div</div>
If you want to have a database in the browser which works across all platforms consistently, despite each browser having different underlying storage mechanisms try PouchDB. It is great! You can keep it just in your browser session which will persist until the user clears their data OR you can have it persist to a CouchDB database server.
http://pouchdb.com/
There are many good CouchDB providers if you dont want to setup your own although that is simple to do. IBM Cloudant is free until your usage is above $50 per month:
https://cloudant.com/
It is very simple to use, see here. A couple lines of code to create a db object and a few to put / fetch. Then one line each to setup a remote copy and one line to live sync to it.

MEAN / AngularJS app check if object already posted

I have thig angularJS frontend and I use express, node and mongo on the backend.
My situation looks like:
//my data to push on server
$scope.things = [{title:"title", other proprieties}, {title:"title", other proprieties}, {title:"title", other proprieties}]
$scope.update = function() {
$scope.things.forEach(function(t) {
Thing.create({
title: t.title,
//other values here
}, function() {
console.log('Thing added');
})
})
};
//where Thing.create its just an $http.post factory
The HTML part looks like:
//html part
<button ng-click="update()">Update Thing</button>
Then on the same page the user has the ability to change the $scope.things and my problem is that when I call update() again all the things are posted twice because literally thats what I'm doing.
Can someone explain me how to check if the 'thing' its already posted to the server just to update the values ($http.put) and if its not posted on server to $http.post.
Or maybe its other way to do this?
I see a few decisions to be made:
1) Should you send the request after the user clicks the "Update" button (like you're currently doing)? Or should you send the request when the user changes the Thing (using ngChange)?
2) If going with the button approach for (1), should you send a request for each Thing (like you're currently doing), or should you first check to see if the Thing has been updated/newly created on the front end.
3) How can you deal with the fact that some Thing's are newly created and others are simply updated? Multiple routes? If so, then how do you know which route to send the request to? Same route? How?
1
To me, the upside of using the "Update" button seems to be that it's clear to the user how it works. By clicking "Update" (and maybe seeing a flash message afterwards), the user knows (and gets visual feedback) that the Thing's have been updated.
The cost to using the "Update" button is that there might be unnecessary requests being made. Network communication is slow, so if you have a lot of Thing's, having a request being made for each Thing could be notably slow.
Ultimately, this seems to be a UX vs. speed decision to me. It depends on the situation and goals, but personally I'd lean towards the "Update" button.
2
The trade-off here seems to be between code simplicity and performance. The simpler solution would just be to make a request for each Thing regardless of whether it has been updated/newly created (for the Thing's that previously existed and haven't changed, no harm will be done - they simply won't get changed).
The more complex but more performant approach would be to keep track of whether or not a Thing has been updated/newly created. You could add a flag called dirty to Thing's to keep track of this.
When a user clicks to create a new Thing, the new Thing would be given a flag of dirty: true.
When you query to get all things from the database, they all should have dirty: false (whether or not you want to store the dirty property on the database or simply append it on the server/front end is up to you).
When a user changes an existing Thing, the dirty property would be set to true.
Then, using the dirty property you could only make requests for the Thing's that are dirty:
$scope.things.forEach(function(thing) {
if (thing.dirty) {
// make request
}
});
The right solution depends on the specifics of your situation, but I tend to err on the side of code simplicity over performance.
3
If you're using Mongoose, the default behavior is to add an _id field to created documents (it's also the default behavior as MongoDB itself as well). So if you haven't overridden this default behavior, and if you aren't explicitly preventing this _id field from being sent back to the client, it should exist for Thing's that have been previously created, thus allow you to distinguish them from newly created Thing's (because newly created Thing's won't have the _id field).
With this, you can conditionally call create or update like so:
$scope.things.forEach(function(thing) {
if (thing._id) {
Thing.update(thing._id, thing);
}
else {
Thing.create(thing);
}
});
Alternatively, you could use a single route that performs "create or update" for you. You can do this by setting { upsert: true } in your update call.
In general, upsert will check to see if a document matches the query criteria... if there's a match, it updates it, if not, it creates it. In your situation, you could probably use upsert in the context of Mongoose's findByIdAndUpdate like so:
Thing.findByIdAndUpdate(id, newThing, { upsert: true }, function(err, doc) {
...
});
See this SO post.
#Adam Zemer neatly addressed concerns I raised in a comment, however I disagree on some points.
Firstly, to answer the question of having an update button or not, you have to ask yourself. Is there any reason why the user would like to discard his changes and not save the work he did. If the answer is no, then it is clear to me that the update should not be place and here is why.
To avoid your user from loosing his work you would need to add confirmations if he attempts to change the page, or close his browser, etc. On the other if everything is continuously saved he has the peace of mind that his work is always saved and you dont have to implement anything to prevent him from loosing his work.
You reduce his workload, one less click for a task may seem insignificant but he might click it many time be sure to have his work save. Also, if its a recurrent tasks it will definitely improve his experience.
Performance wise and code readability wise, you do small requests and do not have to implement any complicated logic to do so. Simple ng-change on inputs.
To make it clear to him that his work is continuously save you can simply say somewhere all your changes are saved and change this to saving changes... when you make a request. For exemple uses, look at office online or google docs.
Then all you would have to do is use the upsert parameter on your mongoDB query to be able to create and update your things with a single request. Here is how your controller would look.
$scope.update = function(changedThing) { // Using the ng-change you send the thing itself in parammeter
var $scope.saving = true; // To display the saving... message
Thing.update({ // This service call your method that update with upsert
title: changedThing.title,
//other values here
}).then( // If you made an http request, I suppose it returns a promise.
function success() {
$scope.saving = false;
console.log('Thing added');
},
function error() {
//handle errors
})
};

How to make a simple database query in Meteor

Every time I have a new idea for an application, I start with Meteor. And every time I end up using something else. And I think it comes down to me not knowing how to do a simple database query.
Here's a hypothetical example. I want to make an app where the user types something into a box, presses a button, and then an image of whatever they typed in shows up. It uses some image search api.
<template name="image">
<input type="text" class="description"></input>
<button class="showImage"></button>
<img src="{{img}}"></img>
</template>
Seems simple enough so far. Now there isn't a way to send information to the client without putting it in a database first, as is my understanding. Let's assume we have some function addToDB that takes queries and enters the image information into the database.
Template.image.events({
'click .showImage': function() {
addToDB($('.description').val());
}
});
Great! That's still not too bad. But now to send the data back to the client...
//server.js
Meteor.publish("image", function(query) {
Images.find({q: query});
}
But wait. We can't just subscribe when the client loads, because we don't know the query yet. So maybe the event handler needs to be
Template.image.events({
'click .showImage': function() {
addToDB($('.description').val());
Deps.autorun(function() {
Meteor.subscribe("images", $('.description').val());
});
}
});
Okay, let's feed that into the template...
Template.image.img = function() {
return Images.findOne().imgsrc;
}
Nope, that results in an error because when the template is first loaded, we haven't subscribed to Images yet. So we can update the template like so:
<template name="image">
<input type="text" class="description"></input>
<button class="showImage"></button>
{{#each info}}
<img src="{{info.img}}"></img>
{{/each}}
</template>
And then change the template filling function to:
Template.image.info = function() {
return Images.find({}, {limit: 1});
}
And voila!
I spent longer than I'm willing to admit stumbling through all of that this evening. If it was just plain old node, I could've used some simple jQuery.
But there are a million amazing features that Meteor has that I really want to take advantage of. So what I'm hoping is that someone can show me the way. What mistakes did I make in this process, and in the final result? What's the nicest, cleanest, simplest way to get this done within a meteor app.
This is so complicated, within a framework that makes so many other things so simple. So how can I just make a simple database query?
Consider looking at the meteor examples they provide. All of the examples have the functionality of taking user input, managing collections, and displaying collection queries to templates.
Most of your code looks fine but you are asking several questions at once and starting from a perspective that makes it difficult to answer. Some general notes:
consider using Session to hold variables a user sets with an event.
subscribe to the data you want by passing Session variable to a Deps.autorun function
display the data you want by passing a Session variable to the template.
basic javascript rules still apply - null.someThingIWant is an error. A handy pattern is return something && something.someThingIWant;
One problem in the code above is that your publish is not returning the query results. I assume that is a typo.

Categories

Resources