Ember JS + Ember Data: Sideloading doesn't work with string ids - javascript

I'm using ember rc3 and ember-data 12 (sha e324f0e) (basically the files recommended in the guides). I have 2 models set up as follows:
App.User = DS.Model.extend({
username: DS.attr('string'),
playerType: DS.attr('string'),
cars: DS.hasMany('App.Car')
})
App.Car = DS.Model.extend({
name: DS.attr('string'),
thumb: DS.attr('string'),
user: DS.belongsTo('App.User')
})
The json returned is
{
"cars": [
{
"id": "50ace47234fa7557403e7f02",
"name": "Dodge Charger SRT8",
"thumb": "/static/images/carthumbs/18331.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "508668cc34fa753b78784ca2",
"name": "BMW M3 Coup\u00e9",
"thumb": "/static/images/carthumbs/23250.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "50c7545334fa750ab8cb3ac2",
"name": "BMW Z4 M Coup\u00e9",
"thumb": "/static/images/carthumbs/7618.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "50adf64c34fa750bb036121e",
"name": "2013 Ford Shelby GT500\u2122",
"thumb": "/static/images/carthumbs/24824.png",
"user_id": "502a754b34fa75280c000a7e"
}
],
"user": {
"id": "502a754b34fa75280c000a7e",
"car_ids": [
"50ace47234fa7557403e7f02",
"508668cc34fa753b78784ca2",
"50c7545334fa750ab8cb3ac2",
"50adf64c34fa750bb036121e"
],
"player_type": "Standard Player",
"username": "WillMckenzie"
}
}
Everything seems to load fine if I call App.User.find("502a754b34fa75280c000a7e"), but when I try and access the cars property on the user it triggers a second http request to the cars api route. It was my understanding that this shouldn't be necessary, and if I change the ids to basic ints, it doesn't. As I'm using Mongo as my DB my ids have to be in this string format.
Any suggestions as to what I'm doing wrong?
Cheers
Will

Here's the answer so people don't have to dig through the comments:
"I had one car id listed that wasn't in the list of cars returned. They're grabbed slightly differently and I obviously had a bad record in there. This meant it always thought it needed to reload that record so would keep requesting. Obviously when I was faking the integer ids it was masking this." - OiNutter

Related

How do I update only certain keys of existing objects in Mongodb?

So this is my case:
In my angular 8 application i create invoices. this is an invoice object:
{
"_id": {
"$oid": "5ea9ad58f65d8d49841362bd"
},
"details": [
{
"_id": "5ea1eff27a1fcb29c4e7d1b6",
"Client": "test",
"km": 88,
"Subject": "test",
"Location": "test",
"StartTime": "2020-04-27T09:00:00.000Z",
"EndTime": "2020-04-27T17:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "oekfokef",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 2,
"CreatedBy": "bob"
},
{
"_id": "5ea1f36297a9a315bc8ed078",
"Client": "test",
"km": 88,
"Subject": "ewfwefwe",
"Location": "fwefwefwefewfwefwef",
"StartTime": "2020-04-20T09:00:00.000Z",
"EndTime": "2020-04-20T17:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "wefwefewfwef",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 3,
"CreatedBy": "bob"
},
{
"_id": "5ea1f38d97a9a315bc8ed083",
"Client": "test2",
"km": 38,
"Subject": "test",
"Location": "test",
"StartTime": "2020-05-04T09:00:00.000Z",
"EndTime": "2020-05-04T16:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "test",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 4,
"CreatedBy": "bob"
}
],
"client": "Robin",
"hoursWorked": 75,
"kmsTravelled": 880,
"invoiceDate": "2020-04-29T16:37:44.948Z",
"paid": "false",
"subTotal": 3917.2,
"travelexpenses": 167.2,
"tax": 879.7,
"hoursCosts": 3750,
"total": 4796.9,
"createdBy": "bob",
"__v": 0
}
But during the use of the application, certain properties change value, like hoursWorked, total, kmTravelled, hourCosts and details. The updated objects get printed to the console. So whenever the user opens the component, i want it to post the whole object, but if an invoice with that Client name alread exists , only update those properties of each invoice per client.
the updated object is this.invoice:
this.invoice = {
client: element.Client,
hourCosts: (element.difference)*this.Client.price,
hoursWorked: (element.difference),
kmsTravelled: element.km,
travelexpenses: this.Client.kmPrice* element.km,
subTotal: (this.Client.kmPrice* element.km) + ((element.difference)*this.Client.price),
total: ((this.Client.kmPrice* element.km) + ((element.difference)*this.Client.price)) + ((this.Client.kmPrice* element.km)+((element.difference)*this.Client.price) * this.tax/100),
createdBy: this.userName,
details: this.details
}
So how do I go about this? Sorry for a quite vague question, but i stuck with this quite a while now. If you need more info please let me know
You could query by 'id' to search for specific values that have changed with something like: db.getCollection('hourCosts').find({_id:'5ea9ad58f65d8d49841362bd'})
Searching in a collection by id with .find() will be efficient. There's a really helpful mongoose doc page here.
Also, just clarifying, you're posting the full customer schema if the name is unique, otherwise updating the relevant invoices by 'client', is that correct? The doc page linked should be useful for most query types and you can create additional mongoose schemas for some added granularity in what content you change.
you can use mongoDB $set in the update command, example:
db.city.update({_id:ObjectId("584a13d5b65761be678d4dd4")}, {$set: {"citiName":"Jakarta Pusat"}})
make sure you are passing the _id as ObjectId
https://www.djamware.com/post/58578ab880aca715e80d3caf/mongodb-simple-update-document-example

MongoDB aggregate function is not returning the value of collection joined using JavaScript

I needed assistance in order to work out why the aggregate function is not responding the way I'd expect it to respond. This is a RESTful API service I've designed in which I am trying to connect collections with each other. Please note the following:
Collection: Season
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81"
}
Collection: Play
{
"_id": {
"$oid": "5c0fc4aafb6fc04dd6ea4d81"
},
"Name": "It was the first time",
"Description": "One of the best action heros in the entertainment industry until this day",
"ReleaseDate": "24/12/2010",
"EndingDate": "12/08/2012",
"Category": "Drama"
}
My implemented code in JavaScript
function getTestLookUp(db, collectionName, response, secondCollectionName){
console.log('First collection name: ' + collectionName + '\n' + 'Second collection name: ' + secondCollectionName);
db.collection(collectionName).aggregate([
{
$lookup:
{
from: secondCollectionName,
localField: 'PlayID',
foreignField: '_id',
as: 'requestedDetails'
}
}
]).toArray((err, res) => {
if(err){
console.log(err);
} else {
console.log(res);
response.status(200).json({
'Items': res
});
}
});
}
The response
{
"Items": [
{
"_id": "5c0fc60bfb6fc04dd6ea4e9a",
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81",
"requestedDetails": []
}
]
}
The things I've checked so far: the collection names are accurate, the ID is also accurate as I can search it up on the MLabs search feature. I don't understand as to why this is returning a empty 'requestedDetails' as I hoped it would return the item from the Play collection.
In addition to this, I would also appreciate if someone can point out how I can join multiple collections instead of 2.
I welcome any questions regarding this problem.
While still researching for this issue, I accidentally came across a another problem in which someone wrote a comment stating that "you might be comparing a String with ObjectID". This was the cause for this error as I obtain a String variable in return from the database and I am comparing the String variable with the _id which is expecting to see a ObjectID variable to complete the query. Therefore, meaning that my query/lookup is never matching these two variables.
The only way tackle this issue is to do a conversion (string to ObjectID) and then compare the values. However, since I'm using the version of ^3.1.10 of MongoDB, this functionality is not possible. Will need to update the version to 4.0 to be able to implement this functionality.
In order to rectify this issue, I managed to surround the foreign ID within $iod tags.
Before
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81"
}
After
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": {
"$oid": "5c0fc4aafb6fc04dd6ea4d81"
}
}
Response
{
"Items": [
{
"_id": "5c0fc60bfb6fc04dd6ea4e9a",
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81",
"Details": [
{
"_id": "5c0fc4aafb6fc04dd6ea4d81",
"Name": "It was the first time",
"Description": "One of the best action heros in the entertainment industry until this day",
"ReleaseDate": "24/12/2010",
"EndingDate": "12/08/2012",
"Category": "Drama"
}
]
}
]
}

Redux state tree structure: "same type of data with different format / amounts of detail"

I've done Dan Abramov's intro series on EggHead, and am working on a real world app. The domain is complex, so I'll run with a classic "blogs" example.
Let's say, we have an "index / list" page, where all we need to show are the blog post's title and blurb. So we have an API endpoint that returns that, and we store it in our state tree under blogs.byId.
Then, when you click through on a blog post, we actually need a bunch more info - e.g. the full blog post, and also tags and categories. Let's call this "blogs with metadata".
Stretching the example, there might be another completely separate page where I want to display a list of blog posts with the most recent 3 comments. Let's call this "blogs with comments".
My question is, how should my state tree treat these separate examples where I'm storing the same "thing" but in different "formats"? My initial hunch would be to treat them as completely separate data types, so my state tree would have eg: blogs.byId, blogsWithMetadata.byId and blogsWithComments.byId.
And then, even if every single blog post is cached in the blogs.byId section, the minute we need to view a blog post, the app completely ignores that warm blogs.byId cache, and looks only at blogsWithMetadata.byId - so we'd essentially be building up 3 separate caches of blog data, each with different amounts of info, and treating it as though they are as unrelated to each other as "blogs" and a completely unrelated table like "widgets" would be.
Is this correct? Or is there a better way?
The app currently rams them all under the same node, without distinction based on "format" and it's causing a world of pain.
There are probably many ways you could choose to do this. One of it is to use normalizr to structure your data.
Your blog post could have a data structure returned by the API like this:
{
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}],
"tags": [{
"id": "1",
"value": "awesome"
}, {
"id": "2",
"value": "journal"
}],
"categories": [{
"id": "1",
"value": "personal"
}, {
"id": "2",
"value": "life"
}]
}
which after normalizing, will look something like this:
{
entities: {
"post": {
"123": {
id: "123",
author: "1",
title: "My awesome blog post",
comments: ["324"],
tags: ["1", "2"],
categories: ["1", "2"],
}
},
"users": {
"1": { "id": "1", "name": "Paul" },
"2": { "id": "2", "name": "Nicole" }
},
"comments": {
"324": { id: "324", "commenter": "2" }
}
"tags": {
"1": { id: "1", "value": "awesome" },
"2": { id: "2", "value": "journal" },
}
"categories": {
"1": { id: "1", "value": "personal" },
"2": { id: "2", "value": "life" },
}
}
}
Subsequently, you could have a state for each page if you needed to:
{
entities: {...},
ui: {
blogs: {
posts: [1, 2],
hasComments: false,
// Displaying the blogs with or without comments
// could simply just be a boolean flag in state.
},
}
}
using reselect, you then create the selectors to pass the posts you want as props to the page Components.

Ember Data 2.1.0 ignores the links property in my JSON response

Ember Data 2.1.0 ignores the links property in my JSON response and fires the following request instead:
/point_logs/3e5ff053422f40e3a8057fc5e8100c47
Also for each point log found it fires a single request. Instead I want it to fetch a collection of all point logs.
In Ember 1.x everything worked fine though. Looked everywhere for an answer but unfortunately I was unable to find a solution so far.
Appliance Model
var DirectObject = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
type: DS.attr('string'),
createdDate: DS.attr('date'),
modifiedDate: DS.attr('date'),
deletedDate: DS.attr('date'),
pointLog: DS.belongsTo('pointLog')
});
Pointlog Model
var PointLog = DS.Model.extend({
unit: DS.attr('string'),
type: DS.attr('string'),
lastConsecutiveLogDate: DS.attr('date'),
updatedDate: DS.attr('date'),
directObject: DS.belongsTo('directObject')
});
JSON Response
{
"data": [
{
"id": "6dbcf32a3e064a36a1db4847329cc90d",
"type": "appliance",
"attributes": {
"name": "3974737",
"description": "",
"type": "zz_misc",
"createdDate": "2015-09-15T14:23:02.768Z",
"modifiedDate": "2015-10-08T08:39:15.525Z",
"deletedDate": null
},
"relationships": {
"pointLog": {
"data": {
"id": "3e5ff053422f40e3a8057fc5e8100c47",
"type": "pointLog"
},
"links": {
"related": "/core/appliances/6dbcf32a3e064a36a1db4847329cc90d/point_log"
}
}
}
}
],
"included": [],
"links": {
"self": "/core/appliances"
}
}
I've also tried using the self property instead of related. And also related as an object with an href property inside being the url.
Ok so I figured it out. The problem is the data property. It seems that if it is present, Ember will make individual calls without using the url given in the links object.
Before
"relationships": {
"pointLog": {
"data": {
"id": "3e5ff053422f40e3a8057fc5e8100c47",
"type": "pointLog"
},
"links": {
"related": "/core/appliances/6dbcf32a3e064a36a1db4847329cc90d/point_log"
}
}
}
After
"relationships": {
"pointLog": {
"links": {
"related": "/core/appliances/6dbcf32a3e064a36a1db4847329cc90d/point_log"
}
}
}

Backbone.js design pattern for JSON data

I've got a question about best practice when designing JSON file which will be displayed by Backbone.js. I know that Backbone is completly agnostic in this topic, but maybe someone will give me good advice in this certain situation.
In the end, I need to have some views which will look like this
On 4th of July, in _____ we calebrate ____ day.
___ means a gap in text, where I'll have an text input or select (depends on type) which correctness will be verified.
So, I need to have a JSON file that describes that piece of text.
I thought about something like this
"body": [
{
"preInputText": "On 4th of July, in ",
"postInputText": "",
"answersID": ["1", "2"]
},
{
"preInputText": "we calebrate ",
"postInputText": " day",
"answersID": ["3"]
}
]
"answers": [
{
"ID": "1",
"content": "USA",
"correct": true
},
{
"ID": "2",
"content": "Canada",
"correct": false
},
{
"ID": "3",
"content": "Independent",
"correct": true
}
]
or, maybe simpleier, but not-so-flat
"body": [
{
"preInputText": "On 4th of July, in ",
"postInputText": "",
"answers": [
{
"ID": "1",
"content": "USA",
"correct": true
},
{
"ID": "2",
"content": "Canada",
"correct": false
},
]
}
]
etc…
So, first approach enforce creating two collections, passing them into one view, and checking values beetween them.
The second, just one collection of models that contains both body and answers, but parsing them at initialization and using nested construction.
I don't know is it a bad pratice (to use nested models), but as i read backbone was designed to think in the more flat way.
Maybe there is some kind of another logic? What do you think?
Thanks!
I'm more with the first approach (the flat one) and I don't agree with you that it enforce creating two collections.
You can always create a single collection and override it's parse function, something like this :
var MyCollection = Backbone.Collection.extend({
...
parse: function(resp) {
this.answers = new Backbone.Collection(resp.answers);
return resp.body;
}
});
...
// myCollection is an instance of MyCollection
myCollection.models // refer to questions
myCollection.answers // refer to answers
"body": [
{
"preInputText": "On 4th of July, in ",
"postInputText": "",
"answers" [ { "ID": "1", "content": "USA", "correct": "true"},
{ "ID": "1", "content": "canada", "correct": "false"}
]
},
{
"preInputText": "we calebrate ",
"postInputText": " day",
"answersID": [{ "ID": "3", "content": "Independent", "correct": "true"},
]
}
]
Using this structure, you need to use one collection. Then you can treat each object in this as a model and you can render these using their separate views in a collection view. So need to use nested models here

Categories