Backbone.js adding to Collection - javascript

In Backbone, I have a collection which is populated with some JSON data which looks like below.
[
{
"test1": {
"fistName": "test",
"lastName": "example"
},
"test2": {
"fistName": "test",
"lastName": "example"
}
},
{
"test1": {
"fistName": "test",
"fistName": "example"
},
"test2": {
"fistName": "test",
"fistName": "example"
}
},
]
Currently im trying to add a new model to the collection holding data like the above.
This is the model.
Test = Backbone.Model.extend({
defaults : {
test1: {
firstName: null,
lastName: null
},
test2: {
firstName: null,
lastName: null
}
},
});
Below is what I am trying
var test = new Test({test1: {firstName: $("#test1 option:selected").val(), score: $("#test1lastName").val()}}, {test2: {firstName: $("#test2 option:selected").val(), score: $("#test2lastName").val()}});
myCollection.add(test);
However doing this only populates test1 data and not test2 data. What would be the correct way to add both test1 and test2 data into the model, which could then be added to the collection.
Thanks
UPDATE
Just to clarify, test 1 and 2 are not separate objects, they are relevant to each other and need to be in the same model

Edit, depending on how your model is defined, if you format it as below you might able to debug a little better.
var test = new TFS.Test({
test1: {
firstName: $("#test1 option:selected").val(),,
lastName: '', // code for last name?
score: $("#test1lastName").val()
},
test2: {
firstName: $("#test2 option:selected").val(),
lastName: '',
score: $("#test2lastName").val()
}
});
myCollection.add(test);
I might be able to offer you a little more help if you give a better view of the entire action/process - i.e. what is triggering the creation of these models? Could there be a problem with jQuery, and your document not being ready?

Related

MongooseJS - Insert Subdocument without Validation on Document

I am using Mongoose with Javascript (NodeJS) to read/write to MongoDB. I have a Document (Parent) that has a bunch of Subdocuments (Children) in it. Both my Document and Subdocuments have validation (required: true and a function that validates that the user puts text in the field) defined in their Model.
When attempting to push a new Subdocument into the database, Mongoose rejects my push because validation fails on the Document. This has perplexed me as I am not trying to create a new Document with Subdocument, I am simply trying to push a new Subdocument into an existing Document.
Here is my (example) Mongoose Model:
const mongoose = require('mongoose');
const requiredStringValidator = [
(val) => {
const testVal = val.trim();
return testVal.length > 0;
},
// Custom error text
'Please supply a value for {PATH}',
];
const childrenSchema = new mongoose.Schema({
childId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
birthday: {
type: Date,
required: true,
},
});
const parentSchema = new mongoose.Schema(
{
parentId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
children: [childrenSchema],
},
{ collection: 'parentsjustdontunderstand' },
);
const mongooseModels = {
Parent: mongoose.model('Parent', parentSchema),
Children: mongoose.model('Children', childrenSchema),
};
module.exports = mongooseModels;
I can successfully push a new Child Subdocument into the Parent Document via the following MongoDB command:
db.parentsjustdontunderstand.update({
firstName: 'Willard'
}, {
$push: {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968" }
}
});
However, when I follow the Mongoose documentation Adding Subdocs to Arrays and try to add it via Mongoose, it fails.
For testing purposes, I am using Postman and performing a PUT request against an endpoint.
The following is req.body:
{
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
My code is:
const { Parent } = require('parentsModel');
const parent = new Parent();
parent.children.push(req.body);
parent.save();
What I get back is:
ValidationError: Parent validation failed: firstName: Path `firstName` is required...`
and it lists all of the Parent Document's validation requirements.
I could use some help on what I am doing wrong. For the record, I have looked at this answer on Stackoverflow: Push items into mongo array via mongoose but most examples I see do not show or discuss validation in their Mongoose Models.
EDIT 1
Based on feedback from #j-f, I modified my code to below (moving the body out of req.body and just creating it in code for testing purposes. When I attempt to push the update the way recommended, the record gets inserted, however, I still get a validation error thrown to console:
const parent = await Parent.findOne({firstName: 'Willard'});
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
parent.children.push(child);
parent.save();
ValidationError: Parent validation failed: children.12.firstName: Path `firstName` is required., children.12.lastName: Path `lastName` is required., children.12.birthday: Path `birthday` is required.
ANSWER
#J.F is correct and I am wrong.
This is incorrect:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
This is correct:
const child = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
The record gets inserted into the database and saved but since I was initiating this as a PUT request, I was not properly responding after a successful save with an HTTP 200 OK. Correct code below for the entire solution, however, keep in mind the res.status code is only necessary in this scenario because I was imitating the code via a PUT request.
Mongoose Model:
const mongoose = require('mongoose');
const requiredStringValidator = [
(val) => {
const testVal = val.trim();
return testVal.length > 0;
},
// Custom error text
'Please supply a value for {PATH}',
];
const childrenSchema = new mongoose.Schema({
childId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
birthday: {
type: Date,
required: true,
},
});
const parentSchema = new mongoose.Schema(
{
parentId: {
type: mongoose.Schema.Types.ObjectId,
},
firstName: {
type: String,
required: true,
validate: requiredStringValidator,
},
lastName: {
type: String,
required: true,
validate: requiredStringValidator,
},
children: [childrenSchema],
},
{ collection: 'parentsjustdontunderstand' },
);
const mongooseModels = {
Parent: mongoose.model('Parent', parentSchema),
Children: mongoose.model('Children', childrenSchema),
};
module.exports = mongooseModels;
The following is req.body:
{
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
Code is:
const { Parent } = require('parentsModel');
const parent = await Parent.findOne({firstName: 'Willard'});
parent.children.push(req.body);
parent.save((err, doc) => {
if (err) {
res.status(500).json({
message: 'Error finding active projects',
error: err,
});
} else {
res.status(200).json(doc);
}
});
You can push the children into the parent using a mongo query because into the update, the first object is to find the document where do the push.
The syntaxis is like: update({query},{update},{options}). So you are looking for a document with firstName: 'Willard' and adding the children into it.
Here everything is ok, all fields exists, the parent exists into collection so there is no problem.
But using
const parent = new Parent();
parent.children.push(req.body);
parent.save();
Your parent object is empty (unless the constructor fill all fields, but this is not a good idea I think).
If you try this:
var parent = await model.findOne({firstName: 'Willard'})
parent.children.push(req.body);
parent.save();
Then should works.
In this case, the object parent is retrieved from collection, so it contains all necessary fields.
I'm going to edit to explain better why is not thethe two queries are not the same.
Basically the child object you are trying to save has not the same structure as db.collection.update one. Note that the object child you have create to insert into collection has only one property called children. It doesn't have the necessary properties like firstName...
I'm going to use pure JS to can see what is the console.log() output and to see the differences.
Your mongo query push an object like this (translated to js language):
var array = []
array.push(
children = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
)
console.log(array)
But you are creating the object in this way:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
console.log(child)
Do you see now the difference? One object is the children itself the other object has the property children with the necessary fields.
So let's combinate the two pieces of code:
const child = {
children: {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
}
const children = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
var array = [child,children]
console.log(array)
So, for your code, if you use:
parent.children.push(child.children);
parent.save();
should works. BUT, the best ways is not created the object children inside const child
Try using:
const child = {
"firstName": "Will",
"lastName": "Smith",
"birthday": "9/25/1968"
}
parent.children.push(child);
parent.save();

Map array of objects by ID and update each existing object in the array

I'm trying to make a call, return an array of objects, then loop through each object in the array by the id and make an additional call. With this second fetch, I need to add a new object to each corresponding object within the original array. Please see code samples below and thank you in advance!
Steps:
Pass search params into postSearchPromise
Map over results and store an array of all id's
Pass each id into the getMediaPromise (I've already defined the token)
Add each response object from the getMediaPromise to the corresponding object in the existing array.
Use a reducer to store the final results (This is a React Native app, i'm using a FlatList on the following screen that points to this stored data, looping through the array and displaying the list on screen)
async function search() {
const toSend = {
title,
age,
location
};
try {
const results = await postSearchPromise(token, toSend);
const theUsers = await results.map(getUsers);
function getUsers(item) {
var users = item.id;
return users;
}
const avatars = await getMediaPromise(token, theUsers);
const mapped = await results.map(element => ({avatar: avatars ,...element}));
dispatch({type: 'SEARCH_RESULTS', payload: mapped});
} catch (e) {
console.log("The Error:" , e);
}
}
Currently, this almost works, but "avatar" takes all of the id's from getUsers and sends them in a comma separated list, together at once, inside the "getMediaPromise," - this is not the intent, but I understand why the code is behaving this way. I'm not sure how to loop through each id and add the new object to each existing object in the array.
The search results I start with:
[
{
id: "123",
name: "John",
location: "USA"
},
{
id: "456",
name: "Jane",
location: "USA"
},
{
id: "789",
name: "Jerry",
location: "USA"
}
]
The search results I need to finish with:
[
{
id: "123",
name: "John",
location: "USA",
avatar: {
type: "default",
status: "200",
ok: true,
url: "http://localhost:3000/media/123"
}
},
{
id: "456",
name: "Jane",
location: "USA",
avatar: {
type: "default",
status: "200",
ok: true,
url: "http://localhost:3000/media/456"
}
},
{
id: "789",
name: "Jerry",
location: "USA",
avatar: {
type: "default",
status: "200",
ok: true,
url: "http://localhost:3000/media/789"
}
}
]
I'm open to an entirely different way to do this, but as mentioned above... I'm using a FlatList on the following screen so it's essential that this is a single array of objects so my FlatList can easily loop over the stored data and pull each piece accordingly. Thanks!

Why the structure of mongoose subdocument can be different?

Is it expected behaviour of mongoose, or it shouldn't be like this. So I have 2 schema for users and address. The schema looks like these:
const addressSchema = {
addressLine: { type: String},
city: { type: String},
locations: { type: String, coordinates: [Number] }, <-- subdocument
}
const userSchema = {
name: { type: String },
email: { type: String },
addresses: {
primary: { type: AddressSchema },
others: { type: [AddressSchema] }
}
}
And I try to insert this data:
{
name: "John Doe",
addresses: {
primary: {
addressLine: "Apple Street"
},
others: [
{
addressLine: "Mango Street"
}
]
}
}
Now this is the confusing part. So I didn't include the locations in the input. But the data that saved in my DB looks like this:
{
name: "john Doe",
addresses: {
primary: {
addressLine: "Apple Street"
},
others: [
{
addressLine: "Mango Street",
locations: { <-- this locations suddenly shown!
coordinates: []
}
}
]
}
_id: randomString,
__v: 0
}
Please help, and thank you in advance :D
In this case, locations is automatically added in your subdocument because of coordinates field in it.
Whenever you define an array enter code heretype field in your schema, Mongoose automatically initialises it with empty array if the value is not provided.
And,since you are not passing any value to locations.coordinates, it is initializing it as an empty array.
If you want to test this theory, please remove coordinates from locations, and you will see the difference.

Enyo different collection with same model kind

I have been trying to create two collection with a common model kind. I am getting the following error:
"Uncaught enyo.Store.addRecord: duplicate record added to store for kind app.ImageModel with primaryKey set to id and the same value of 67774271 which cannot coexist for the kind without the ignoreDuplicates flag of the store set to true ".
Following are the two collection i have defined...
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appF",
...
...
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appS",
...
...
});
And the model which i am using is as follows:
enyo.kind({
name: "app.ImageModel",
kind: "enyo.Model",
readOnly: true,
....
....
});
At one point i am setting like this:
this.set("data", new app.FeatureCollection());
and in another,
this.set("data", new app.SearchCollection());
I am not able to find out what could generate the error. I even tried to set "ignoreDuplicates" to true in model...but still the error comes. Any suggestion where i could be going wrong.
The ignoreDuplicates flag is expected to be set on enyo.Store and not enyo.Model:
enyo.store.ignoreDuplicates = true;
Are you using the fetch method of enyo.Collection to retrieve your data? If so, you might consider setting the strategy property to merge in your fetch call so that you have a single record for each unique image from your dataset, i.e.:
myCollection.fetch({strategy: "merge", success: function(rec, opts, res) {
// do something after data is retrieved
}});
I'm not seeing a problem with the pieces of code you provided. I created a sample on jsFiddle and it works as expected.
http://jsfiddle.net/z7WwZ/
Maybe the issue is in some other part of your code?
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.MyModel",
kind: "enyo.Model",
readOnly: true,
defaults: {
firstName: "Unknown",
lastName: "Unknown"
}
});
enyo.kind({
name: "App",
components: [],
bindings: [],
create: enyo.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
this.collection1 = new app.FeatureCollection(this.data1);
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Smith");
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection2 = new app.SearchCollection(this.data2);
enyo.log("Collection2(0) >>> " + this.collection2.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Jones");
enyo.log("Collection2(0) >>> " + this.collection1.at(0).get("lastName"));
};
}),
data1: [{
firstName: "Hall",
lastName: "Caldwell"
}, {
firstName: "Felicia",
lastName: "Fitzpatrick"
}, {
firstName: "Delgado",
lastName: "Cole"
}],
data2: [{
firstName: "Alejandra",
lastName: "Walsh"
}, {
firstName: "Marquez",
lastName: "James"
}, {
firstName: "Barr",
lastName: "Lott"
}]
});
new App().renderInto(document.body);

Making template html for json data

I am using t.js as a template engine in my project. How to make template for this json:
{
data: [
{
FirstName: "Test1",
LastName: "Test11"
},
{
FirstName: "Test2",
LastName: "Test22"
},
{
FirstName: "Test3",
LastName: "Test33"
}
]
}
I want to render it like
<ul>
<li>Test1,Test11</li>
<li>Test2,Test22</li>
<li>Test3,Test33</li>
</ul>
Can you suggest any other template engine along with template html for my above case which is better? I don't want to use any template engine using eval or new Func
Markup
<ul id="myList">
{{#mydata}} <li>{{=_val.FirstName}},{{=_val.LastName}}</li> {{/#mydata}}
</ul>
Javascript
var source = $("#myList").html();
var template = new t(source);
$("#myList").html(template.render({
mydata: [
{
FirstName: "Test1",
LastName: "Test11"
},
{
FirstName: "Test2",
LastName: "Test22"},
{
FirstName: "Test3",
LastName: "Test33"
}
]
}));
demo : http://jsfiddle.net/diode/c2Qhw/

Categories