Backbone nested collection - javascript

I have an app in backbone that retrieve data from a server. This data are hotels and foreach hotel I have more rooms. I have divided hotel into a json and rooms inside another json like this:
hotel.json
[
{
"id": "1",
"name": "Hotel1"
},
{
"id": "2",
"name": "Hotel2"
},
{
"id": "3",
"name": "Hotel3"
}
]
rooms.json
[
{
"id" : "r1",
"hotel_id" : "1",
"name" : "Singola",
"level" : "1"
},
{
"id" : "r1_1",
"hotel_id" : "1",
"name" : "Doppia",
"level" : "2"
},
{
"id" : "r1_3",
"hotel_id" : "1",
"name" : "Doppia Uso singol",
"level" : "1"
},
{
"id" : "r2",
"hotel_id" : "2",
"name" : "Singola",
"level" : "1"
},
{
"id" : "r2_1",
"hotel_id" : "2",
"name" : "Tripla",
"level" : "1"
}
]
I wanna take each hotel and combine with its rooms (external key into rooms.json hotel_id) and print the combination of the rooms: foreach level combine different rooms.
One room of level 1, one room of level 2 and one room of level 3.
Maximum of level is 3 but I can have only one level or only two level.
If I have 3 level I don't want combination of level 1 and level 2 without level 3.
Something like this
Room "Single", "level" : "1" , "hotel_id" : "1"
Room "Double", "level" : "2" , , "hotel_id" : "1"
Room "Triple", "level" : "3" , , "hotel_id" : "1"
Room "Double for single", "level" : "1" , "hotel_id" : "1"
Room "Double", "level" : "2" , , "hotel_id" : "1"
Room "Triple", "level" : "3" , , "hotel_id" : "1"
The constructor of this rooms I think is to put into renderRooms into my app.
This is my app:
var Room = Backbone.Model.extend();
var Rooms = Backbone.Collection.extend({
model: Room,
url: "includes/rooms.json"
});
var Hotel = Backbone.Model.extend({
defaults: function() {
return {
"id": "1",
"name": "Hotel1",
"rooms": []
}
}
});
var HotelCollection = Backbone.Collection.extend({
model: Hotel,
url: "includes/test-data.json",
initialize: function() {
console.log("Collection Hotel initialize");
}
});
var HotelView = Backbone.View.extend({
template: _.template($("#hotel-list-template").html()),
initialize: function() {
this.collection = new HotelCollection();
this.collection.bind('sync', this.render, this);
this.collection.fetch();
},
render: function() {
console.log('Data hotel is fetched');
this.bindRoomToHotel();
var element = this.$el;
element.html('');
},
bindRoomToHotel: function() {
allRooms = new Rooms();
allRooms.on("sync", this.renderRooms, this)
allRooms.fetch();
},
renderRooms: function() {
$(this.el).html(this.template({ hotels: this.collection.models }));
}
});
var hotelView = new HotelView({
el: $("#hotel")
});
How can I create this room combination and print it?
Is there a good way or there is something better?

Here is how you can structure the Collections:
HotelModel = Backbone.Model.extend({
initialize: function() {
// because initialize is called after parse
_.defaults(this, {
rooms: new RoomCollection
});
},
parse: function(response) {
if (_.has(response, "rooms")) {
this.rooms = new RoomCollection(response.rooms, {
parse: true
});
delete response.rooms;
}
return response;
},
toJSON: function() {
var json = _.clone(this.attributes);
json.rooms = this.rooms.toJSON();
return json;
}
});
RoomModel = Backbone.Model.extend({
});
HotelCollection = Backbone.Collection.extend({
model: HotelModel
});
RoomCollection = Backbone.Collection.extend({
model: RoomModel
});
Then you can do something like this:
var hotels = new HotelCollection();
hotels.reset([{
id: 1,
name: 'Hotel California',
rooms: [{
id: 1,
name: 'Super Deluxe'
}]
}], {
parse: true // tell the collection to parse the data
});
// retrieve a room from a hotel
hotels.get(1).rooms.get(1);
// add a room to the hotel
hotels.get(1).rooms.add({id:2, name:'Another Room'});

Related

How to find data on MongoDB by passing part of array objects

I tried to create an API for filtering the products by sending an array of objects as filters.
this is my Product schema:
const mongoose = require("mongoose");
const { s, rs, rn, rref, ref } = require("../utils/mongo");
let schema = new mongoose.Schema(
{
user: rref("user"),
name: rs,
description: s,
images: [s],
price: rn,
category: ref("category"),
filters: [
{
parent: ref("filter"),
value: s,
name: s,
},
],
subFilter: [
{
parent: s,
value: s,
title: s,
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("product", schema);
and this one is what I want to send as body to the API
{
category: '62445c3d922d127512867245'
filters: [
{ name: 'filter name 1', value: '62445c3d922d127512861236' },
{ name: 'filter name 2', value: '62445c3d922d127512861458' },
.....
]
}
as you see I want to filter my products based on category Id and an array of filter objects. I tried to write this query but it return an empty array.
this is my query:
filter: async (req, res) => {
try {
const { category, filters } = req.body;
const products = await Product.find({
category,
filters: {
$in: filters,
},
});
res.status(200).json(products);
} catch (err) {
res.status(500).json(err);
}
},
what stored on db
{
"_id" : ObjectId("62643acf19636d7db1804cb3"),
"images" : [
"image-1650735823476۸.jpg"
],
"user" : ObjectId("622606af0f40cb8ea37383dc"),
"name" : "شیر توپی 2 اینچ کلاس 150 پیشگام",
"description" : " برند پیشگام با مدارک و تاییدیه ",
"price" : NumberInt(5000000),
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
{
"_id" : ObjectId("62643acf19636d7db1804cb4"),
"parent" : ObjectId("6264307f19636d7db1804b77"),
"value" : "626430bb19636d7db1804b78",
"name" : "Valve Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb5"),
"parent" : ObjectId("6264319819636d7db1804b7b"),
"value" : "6264319819636d7db1804b7e",
"name" : "Body Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb6"),
"parent" : ObjectId("626431ef19636d7db1804b82"),
"value" : "626431ef19636d7db1804b83",
"name" : "Bore Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb7"),
"parent" : ObjectId("6264328519636d7db1804b85"),
"value" : "6264328519636d7db1804b86",
"name" : "Material Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb8"),
"parent" : ObjectId("626435de19636d7db1804c10"),
"value" : "626439b619636d7db1804ca7",
"name" : "Trim Material"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb9"),
"parent" : ObjectId("6264367919636d7db1804c17"),
"value" : "6264367919636d7db1804c18",
"name" : "End Conection"
},
{
"_id" : ObjectId("62643acf19636d7db1804cba"),
"parent" : ObjectId("626436a719636d7db1804c1f"),
"value" : "6264378119636d7db1804c28",
"name" : "Size"
},
{
"_id" : ObjectId("62643acf19636d7db1804cbb"),
"parent" : ObjectId("6264389219636d7db1804c6d"),
"value" : "6264389219636d7db1804c6f",
"name" : "Class / Pressure"
}
],
"subFilter" : [
{
"_id" : ObjectId("62643acf19636d7db1804cbc"),
"parent" : "6264328519636d7db1804b85",
"value" : "626433b919636d7db1804b93",
"title" : "Body Material"
}
],
"createdAt" : ISODate("2022-04-23T17:43:43.421+0000"),
"updatedAt" : ISODate("2022-04-23T17:53:29.016+0000"),
"__v" : NumberInt(0)
}
Consider this shrunk down set of inputs that capture the essence of the question. The comments "give away" what we are going to try to find and why. We only show one value for category because matching on that is trivial and not the interesting part of the query.
[
{
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
// Matching Valve/value; include this doc
{"name" : "Valve", "value" : "626430bb19636d7db1804b78"},
// ALSO match Body/value; include this doc (but needs only 1 match)
{"name" : "Body", "value" : "6264319819636d7db1804b7e"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
// Not target value for Valve name (..79 instead of ...78):
{"name" : "Valve", "value" : "626430bb19636d7db1804b79"},
// ...but correct value for Body, so include this doc
{"name" : "Body", "value" : "6264319819636d7db1804b7e"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
// No matching Valve or Body so this whole doc is ignored.
"filters" : [
{"name" : "Valve", "value" : "626430bb19636d7db1804b79"},
{"name" : "Body", "value" : "6264319819636d7db1804b7f"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
// Not even name matches so ignore this too:
"filters" : [
{"name" : "Pipe", "value" : "6264319819636d7db1804eee"}
]
}
]
Assume also we set up inputs coming from the API like this, in their native form i.e. strings NOT ObjectId:
var targ_cat = '62445c4d922d127512867246';
var any_one_of = [
{ name: 'Valve', value: '626430bb19636d7db1804b78' },
{ name: 'Body', value: '6264319819636d7db1804b7e'}
];
We will use $filter as our main function but to do so, we must convert the incoming material into a form required by $filter.
// Convert inbound array of any_one_of into a something designed to work
// in the $filter function by comparing each name/value entry in the
// filters field to the item presented in $$this, meaning take:
// { name: 'Valve', value: '626430bb19636d7db1804b78' },
// and turn it into:
// {$and: [ {$eq:['Valve','$$this.name']}, {$eq:['62643...','$$this.value']} ] }
// Since any one of the entries is considered a hit, we package it all
// into an $or wrapper, not $and.
var or_list = [];
any_one_of.forEach(function(f) {
or_list.push( {$and: [
{$eq:[f['name'], '$$this.name']},
{$eq:[f['value'], '$$this.value']}
]});
});
var or_expr = {$or: or_list};
Now we are ready to query mongoDB:
db.foo.aggregate([
// Get this out of the way quickly; note we must make a new ObjectId!
{$match: {'category': new ObjectId(targ_cat)}}
// The interesting part of the query:
,{$addFields: {filters: {$filter: {input: '$filters', cond: or_expr}}}}
// Only keep those items where $filter found at least one of the
// targets:
,{$match: {$expr: {$gt:[{$size: '$filters'},0]} }}
]);

Mongodb mapreduce Join 2 collections

I have 2 collections and I am new to Mongo MapReduce concept.
My collection Value looks like this
{
"_id" : ObjectId("5bc4f20e1a80d2045029ccb7"),
"name" : "Title 1",
"value" : "value 1 for title 1"
}
{
"_id" : ObjectId("5bc4f20e1a80d2045029ccb8"),
"name" : "Title 1",
"value" : "Value 2 for title1. "
}
{
"_id" : ObjectId("5bc4f20e1a80d2045029ccb9"),
"name" : "Title 2",
"value" : " Definitely a motivational text!"
}
{
"_id" : ObjectId("5bc4f20e1a80d2045029ccba"),
"name" : "Title 2",
"value" : "It's tough but I'm carrying on. "
}
Other collection Details look like:
{
"_id" : ObjectId("5bc4f2361a80d2045029d05b"),
"name" : "Title 1",
"totalValues" : 6.0000000000000000,
"link": "Link1",
"description" : "Some More Text to Make title 1 look better"
}
{
"_id" : ObjectId("5bc4f2361a80d2045029d2eb"),
"name" : "Title 2",
"totalValues" : 2,
"link": "Link2",
"description" : "Some More Text to Make title 2 look better"
} ...
I want the output result as
{
“name” : “XXXXXXXX”,
“comments” : [ {“value”: “XXXXXXX”}, {“value”: “YYYYYYYY”}],
“totalValues” : 2,
“link”: “XXXXXXXXXX”,
“description”: “XXXXXXXXXXXXXXXXXX”
}
with the following output document. Please help.
I have tried following code:
var mapDetails = function(){
var output = {name: this.name,totalValues :this.totalValues, description : this.description, link :this.link}
emit(this.name, output);
};
var mapGpas = function() {
emit(this.name,{name:this.name, value:this.value, totalValues:0, description: 0, link: 0});
};
var r = function(key, values) {
var outs = { name: 1,value: 1, description: 0,totalValues:0, link: 0};
values.forEach(function(v){
outs.name = v.name;
if (v.value == 0) {
outs.description = v.description;
outs.totalValues = v.totalValues;
outs.link = v.link;
}
});
return outs;
};
res = db.Value.mapReduce(mapGpas, r, {out: {reduce: 'joined'}})
res = db.Details.mapReduce(mapDetails, r, {out: {reduce: 'joined'}})
db.joined.find().pretty()

firebase grab by orderByChild then update results key

So i have this query and currently collects all the data with materialName equals to gold. I wanted change all to false.
// materialName = "gold" for example
database.ref('/app/posts').orderByChild('material').startAt(materialName).endAt(materialName).once('value', function (snapshot) {
const materials = snapshot.val();
})
I have tried something like this:
database.ref('/app/posts').orderByChild('material').startAt(materialName).endAt(materialName).once('value', function (snapshot) {
database.ref('/app/posts').update({material: false});
})
also I have tried this:
const newData = Object.assign({}, materials, {material: false});
// but this updates outside of the post, result will be:
"posts" : {
"material": false,
"post-1503586" : {
"title": "sample title",
"material" : "gold"
},
"post-9172991" : {
"title": "sample title",
"material" : "silver"
}
}
sample json:
"posts" : {
"post-1503586" : {
"title": "sample title",
"material" : "gold"
},
"post-9172991" : {
"title": "sample title",
"material" : "silver"
}
}
You need to loop over the results (since there can be multiple matching nodes) and then update each:
database.ref('/app/posts')
.orderByChild('material')
.equalTo(materialName)
.once('value', function (snapshot) {
snapshot.forEach(function(child) {
child.ref.update({material: false});
});
});
You'll also note that I changed your .startAt().endAt() to an equalTo(), which gives the same results with less code.

How to save data in the form of Mongodb Nested schema using mongoose

I want to structure mongodb in such a way that it store data in following way.
{
"question" : "Was today's decision right?",
"choices" : [
{
"text" : "yes",
"votes" : [
{
"ip" : "123.123.123.123",
"time" : "123444"
}
]
},
{
"text" : "no",
"votes" : [
{
"ip" : "123.123.123.123",
"time" : "123444"
},
{
"ip" : "123.123.123.123",
"time" : "123444"
},
{
"ip" : "123.123.123.123",
"time" : "123444"
}
]
}
]
},
{
"question" : "Was yesterday's decision right?",
"choices" : [
{
"text" : "yes",
"votes" : [
{
"ip" : "123.123.123.123",
"time" : "123444"
}
]
},
{
"text" : "no",
"votes" : [
{
"ip" : "123.123.123.123",
"time" : "123444"
},
{
"ip" : "123.123.123.123",
"time" : "123444"
},
{
"ip" : "123.123.123.123",
"time" : "123444"
}
]
}
]
}
What i have done so far for structure after little searching
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var voteSchema = new Schema({
ip: String
});
var choiceSchema = new Schema({
text: String,
votes: [voteSchema]
});
var PollSchema = new Schema({
question: { type: String, required: true },
choices: [choiceSchema]
});
module.exports = mongoose.model('Polls', PollSchema);
Now if I use following code to save hard coded data then it's working fine
var poll = new Poll({
question : reqBody.question,
choices : [
{
text : "yes",
votes : [
{
ip : "123.123.123.123"
}
]
},
{
text : "no",
votes : [
{
ip : "123.123.123.123",
},
{
ip : "123.123.123.123",
},
{
ip : "123.123.123.123",
}
]
}
]
});
poll.save(function(err, data) {
res.json(data);
});
But i am not able to figure how i should send data from front end (html/js)?
Got solution :
First put the following code in controller file
var reqBody = req.body;
var choices = reqBody.choices;
var choicesnew = [];
for (var i = choices.length - 1; i >= 0; i--) {
var votes = [];
var choice = {text:choices[i],votes: votes};
choicesnew.push(choice);
}
var newPoll = {
question: reqBody.question,
choices: choicesnew
}
var poll = new Poll(newPoll);
poll.save(function(err, data){
res.json(reqBody);
});
And now pass the data using front end
<form action="#">
<input type="text" name="question" placeholder="question">
<input type="text" name="choices" placeholder="choices">
<input type="text" name="choices" placeholder="choices">
<input type="text" name="choices" placeholder="choices">
<input type="text" name="ip" placeholder="ip">
<input type="submit">
</form>
Although some data should be processed by nodejs. I am just listing here just for the sake of simplicity.
Now i am using ajax to send data from front end to node
$("form").on('submit', function(event) {
event.preventDefault();
$.ajax({
url: '/new',
type: 'POST',
data: $(this).serializeArray(),
})
.done(function(data) {
console.log(data);
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
});

Dojo Tree based on ItemFileReadStore and parent-based model

I'm trying to programmatically create a dojo tree from a json file. The problem is that my json objects reference to their parents not children as in some examples.
Unfortunately my output looks only like this:
I have the following javascript code:
<script type="text/javascript">
require(["dijit/Tree", "dojo/data/ItemFileReadStore", "dijit/tree/ForestStoreModel", "dijit/tree/ObjectStoreModel", "dojo/domReady!"],
function(Tree, ItemFileReadStore, ObjectStoreModel, ForestStoreModel){
var store = new ItemFileReadStore({
url: "/_data/test.json",
getChildren: function(object){
return this.query({F_TopLevelCategoryID: object.P_CategoryID});
}
});
var myModel = new ObjectStoreModel({
store: store,
labelAttr:'CategoryName',
query: {"P_CategoryID": 0}
});
var myTree = new Tree({
model: myModel
}, "treeOne");
myTree.startup();
});
</script>
The json file looks like the following:
{ "identifier" : "P_CategoryID",
"label" : "CategoryName",
"items" : [ { "CategoryName" : "Category 1",
"F_TopLevelCategoryID" : 0,
"P_CategoryID" : 1
},
{ "CategoryName" : "Category 2",
"F_TopLevelCategoryID" : 1,
"P_CategoryID" : 2
},
{ "CategoryName" : "Category 3",
"F_TopLevelCategoryID" : 1,
"P_CategoryID" : 3
},
{ "CategoryName" : "Category 4",
"F_TopLevelCategoryID" : 1,
"P_CategoryID" : 4
},
{ "CategoryName" : "Category 5",
"F_TopLevelCategoryID" : 3,
"P_CategoryID" : 5
},
{ "CategoryName" : "Category 6",
"F_TopLevelCategoryID" : 4,
"P_CategoryID" : 6
},
{ "CategoryName" : "Category 7",
"F_TopLevelCategoryID" : 4,
"P_CategoryID" : 7
},
{ "CategoryName" : "Category 8",
"F_TopLevelCategoryID" : 0,
"P_CategoryID" : 8
},
{ "CategoryName" : "Top Level Category",
"P_CategoryID" : 0
}
]
}
Where is the problem?
I believe it was a fluke that you received a partial result.
You have forestStoreModel and objectStoreModel transposed in the require block, and referencing parents is fine!
Also, use dojo/store instead of ItemFileReadStore, as the latter is deprecated. Use the data parameter on Memory:
var store = new Memory({
data: testJson,
getChildren: ...
});
See my working fiddle here, using dojo/store/Memory: https://jsfiddle.net/yubp45sa/
You can get your data into the memory store using dojo/request:
request("testData.json").then(...);
http://dojotoolkit.org/reference-guide/1.10/dojo/request.html
I had another request example in previously, which requested the data through a GET from a custom nodeJS route (returning JSON):
request.get("/configInfo", {
handleAs: "json"
}).then(...);

Categories