I'm trying to make a real-time vote application using SailsJS, and am currently having troubles with MongoDB. I am completely new to this, and have been just using SailsJS mimic easy calls to access MongoDB.
module.exports = {
attributes: {
selectOptions:{
type: 'Object'
},
question:{
type:'string',
required: true
},
password:{
type:'string',
required: true
}
}
};
The above code is for the model that I have, and I am the selectOptions should have an array of objects, like [{id: 1,result: 0},{id:2,result 0},...] and would like to know how to do this, as I cannot seem to find any documentation about the array of objects. Only thing I found was something about collection, or making another model and link that to the original model, but when i tried it, sails gave me some foreign key error that I have never faced before. I really really appreciate your time, and look forward for the response.
P.S - I tried making the array into either JSON or Object or nothing(Like not put any type under selectOptions) and made change to the model as well to see if it works, but both JSON and Object didn't work, but selectOptions did. However, I think it was returning a string, as it the length was longer than what the array was supposed to be.
Related
I'm working with JavaScript in Node.js and using Express with some mongoose and following a well known RESTful API tutorial on youtube, I've come to patching the API and have been trying to understand why the following code works for sometime now;
updateItem = {};
for (const changes of req.body) {
updateItem[changes.propName] = changes.value;
}
Product.updateOne({ _id: id }, { $set: updateItem })
The rest is just your standard .then().catch() to send the response status, but I'm lost on how creating the object then placing it before an array works to update a value.
It's my current understanding that the object must be instantiated before use, I couldn't just put brackets there and have it work, even if I wasn't using it to set something later. Then I loop through the changes from the request body which must be an array to allow looping, but here's where I get lost.
Does the array of iterated prop names changes.propName get placed inside the updateItem object which is then set to the changed values from the array of properties that are being changed? Do I need to understand $set syntax more? I'm struggling to pick it apart to make it longer or simpler but better to understand.
This is the json array setup I'm passing for testing through postman if it helps;
[
{
"propName": "name", "value": "placeholder user"
}
]
I was unable to find anything to help me understand the interactions going on here, I haven't seen something like this before either but please redirect me if this has already been asked.
Is there a way to configure a JsonRestStore to work with an existing web service that returns an array of objects which is not at the root-level of the JSON response?
My JSON response is currently similar to this:
{
message: "",
success: true,
data: [
{ name: "Bugs Bunny", id: 1 },
{ name: "Daffy Duck", id: 2 }
],
total: 2
}
I need to tell the JsonRestStore that it will find the rows under "data", but I can't see a way to do this from looking at the documentation. Schema seems like a possibility but I can't make sense of it through the docs (or what I find in Google).
My web services return data in a format expected by stores in Ext JS, but I can't refactor years worth of web services now (dealing with pagination via HTTP headers instead of query string values will probably be fun, too, but that's a problem for another day).
Thanks.
While it's only barely called out in the API docs, there is an internal method in dojox/data/JsonRestStore named _processResults that happens to be easily overridable for this purpose. It receives the data returned by the service and the original Deferred from the request, and is expected to return an object containing items and totalCount.
Based on your data above, something like this ought to work:
var CustomRestStore = declare(JsonRestStore, {
_processResults: function (results) {
return {
items: results.data,
totalCount: results.total
};
}
});
The idea with dojo/store is that reference stores are provided, but they are intended to be customized to match whatever data format you want. For example, https://github.com/sitepen/dojo-smore has a few additional stores (e.g. one that handles Csv data). These stores provide good examples for how to handle data that is offered under a different structure.
There's also the new dstore project, http://dstorejs.io/ , which is going to eventually replace dojo/store in Dojo 2, but works today against Dojo 1.x. This might be easier for creating a custom store to match your data structure.
I successfully implemented loading and showing relations with 'Backbone Relational' from an API I created. I get how things work by trial and error. I do think the docs are lacking some clarity though since it took a lot of time to figure out how things work. Especially on how to map things to the API I think the docs are lacking a bit.
Problem
Adding a bookmark works, it's the editing and deletion that don't work. The PUT becomes a POST and the DELETE simply doesn't fire at all. When I set an id to the model hardcoded it does work. So the id is missing which makes sense for the PUT becoming a POST.
The problem seems to be that the id doesn't hold an actual id, but a collection. The view where the problem occurs does not requires the BookmarkBinding, it's used somewhere else. Simply the fact that it has Bookmark as a relation makes the DELETE and PUT break.
BookmarkBinding model:
App.Model.BookmarkBinding = Backbone.RelationalModel.extend({
defaults: {
set_id: null,
bookmark_id: null
},
relations: [{
type: Backbone.HasOne,
key: 'bookmark',
relatedModel: 'App.Model.Bookmark',
reverseRelation: {
type: Backbone.HasOne,
key: 'id'
}
}],
urlRoot: 'http://api.testapi.com/api/v1/bookmark-bindings'
});
Bookmark model:
App.Model.Bookmark = Backbone.RelationalModel.extend({
defaults: {
url: 'undefined',
description: 'undefined',
visits: 0,
},
relations: [{
type: Backbone.HasMany,
key: 'termbindings',
relatedModel: 'App.Model.TermBinding',
reverseRelation: {
key: 'bookmark_id',
}
}],
urlRoot: 'http://api.testapi.com/api/v1/bookmarks'
});
From Backbonejs.org
The default sync handler maps CRUD to RESTful HTTP methods like so:
create → POST /collection
read → GET /collection[/id]
update → PUT /collection/id
delete → DELETE /collection/id
Your question suggests that you're making an HTTP PUT request, and therefore a Backbone update. If you want to make an HTTP POST, use Backbone create. The PUT request maps onto update, and requires that an id be sent in the URL, which isn't happening according to your server log. If your're creating a new object, then most server-side frameworks such as Rails / Sinatra / Zend will create an id for the object
Another possible source of error is the keys that you chose for the relations, like you suspected.
A Bookmark has many BookmarkBindings, and it seems that Backbone-relational will store them in the field that you specify in BookmarkBindings.relations.reverseRelation.key, which is currently defined as 'id'.
So the collection of related BookmarkBindings ids will to be stored on the same attribute as the Bookmark.id, creating a collision. Backbone.sync will send an undefined value to the server (which you see in your logs), because it finds a collection there instead of an integer.
First suggestion - You may not need a bidirectional relation, in which case drop it from the BookmarkBinding model.
Second suggestion - define the reverse relation on another key, so that it doesn't collide with Bookmark.id, such as BookmarkBindings.relations.reversRelation.key : 'binding_ids'
due disclosure - I've never used Backbone-relational.js, only Backbone.js.
The problem was that on editing or deleting the bookmark model, the bookmark binding model wanted to do it's work too since it is related too the bookmark from it's side. I already tried to remove the reverse relation which didn't prove to be a solution since in the other part of my application where I used the bookmark bindings things wouldn't work anymore.
Solution
I did end up removing the reverse relation (#jarede +1 for that!), but the crux was how to implement the foreign key to fetch relations from the API without a reverse relation. I ended up adding the keySource and keyDestination which made everything work out.
Sidenote
Backbone Ralational cannot handle identical foreign keys either, this gave me some problems too. This will make the lastly declared foreign key overwrite all the previous ones. This can be quite impractical since within an API it's not uncommon that model's are related to a column named id. So the idAttribute can be set with idAttribute: '_id' for example, but the foreign key has to be unique across your application.
BookmarkBinding model:
App.Model.BookmarkBinding = Backbone.RelationalModel.extend({
defaults: {
set_id: null,
bookmark_id: null
},
relations: [{
type: Backbone.HasOne,
key: 'bookmark',
keySource: 'id',
keyDestination: 'bookmark',
relatedModel: 'App.Model.Bookmark'
}],
urlRoot: 'http://api.testapi.com/api/v1/bookmark-bindings'
});
I'm new to Backbone and to MongoDB. I'm running into problems destroying models (that are backed by MongoDB). I believe it has something to do with the fact that a MongoDB "document" uses the abnormal _id attribute and is not wired up with Backbone by default. I've tried setting idAttribute: '_id' which does not seem to solve the issue.
A sample Mongo document looks like:
{
_id: Object
$oid: "527303e82f3504ba5bf4b21f"
__proto__: Object
feeling: "ok"
location: "california"
name: "Kevin"
}
models.coffee
class Models.Campaign extends Backbone.Model
urlRoot: "http://localhost:4567/api/campaigns"
# setting idAttribute: '_id' causes issues rendering the Backbone collection
controller.coffee
...
model.destroy() #=> only removes the item from the dom but does not make a DELETE request
Am I able to pass in an id to the destroy() function?
Does anyone have advise in how to properly wire up Backbone with MongoDB without having to monkeypatch a ton of built-in Backbone functions?
I think you'll have an easier time if you add a parse to your model to sort out the confusing data you're getting from the server. You don't need or care about _id, you do care about $oid, and Backbone would prefer to work with an id property; you can sort out all three with a simple parse in your model like this:
parse: function(response) {
var parsed = _(response).pick(
'feeling',
'location',
'name'
);
parsed.id = response.$oid;
return parsed;
}
Demo: http://jsfiddle.net/ambiguous/pn773/
You'd probably be fine if your parse modified response rather than making a semi-copy using _.pick and modifying that copy, however, parse doesn't technically own response so it would be rude to change it and there could be surprising side effects. Good habits, etc.
Then when Backbone tries to convert the server's data to a model, it will end up working with:
{
id: "527303e82f3504ba5bf4b21f",
feeling: "ok",
location: "california",
name: "Kevin"
}
and everyone should be happy:
Backbone won't see the irrelevant _id.
Backbone won't see $oid and you won't need to set idAttribute to anything special.
Backbone will see an id like it expects and all the standard machinery will use the BSON ObjectId as the model's unique identifier.
The simple method should get you your DELETE /api/campaigns/527303e82f3504ba5bf4b21f request when you model.destroy().
I have read and read the docs on these two methods, but for the life of me cannot work out why you might use one over the other?
Could someone just give me a basic code situation where one would be application and the other wouldn't.
reset sets the collection with an array of models that you specify:
collection.reset( [ { name: "model1" }, { name: "model2" } ] );
fetch retrieves the collection data from the server, using the URL you've specified for the collection.
collection.fetch( { url: someUrl, success: function(collection) {
// collection has values from someUrl
} } );
Here's a Fiddle illustrating the difference.
We're assuming here that you've read the documentation, else it'l be a little confusing here.
If you look at documentation of fetch and reset, what it says is, suppose you have specified the url property of the collection - which might be pointing to some server code, and should return a json array of models, and you want the collection to be filled with the models being returned, you will use fetch.
For example you have the following json being returned from the server on the collection url:
[{
id : 1,
name : "a"
}, {
id : 2,
name : "b"
}, {
id : 3,
name : "c"
}]
Which will create 3 models in your collection after successful fetch. If you hunt for the code of collection fetch here you will see that fetch will get the response and internally will call either reset or add based on options specified.
So, coming back to discussion, reset assumes that we already have json of models, which we want to be stored in collection, we will pass it as a parameter to it. In your life, ever if you want to update the collection and you already have the models on client side, then you don't need to use fetch, reset will do your job.
Hence, if you want to the same json to be filled in the collection with the help of reset you can do something like this:
var _self = this;
$.getJSON("url", function(response) {
_self.reset(response); // assuming response returns the same json as above
});
Well, this is not a practice to be followed, for this scenario fetch is better, its just used for example.
Another example of reset is on the documentation page.
Hope it gives a little bit of idea and makes your life better :)
reset() is used for replacing collection with new array. For example:
#collection.reset(#full_collection.models)
would load #full_collections models, however
#collection.reset()
would return empty collection.
And fetch() function returns default collection of model