NodeJS + Mongoose + Backbone.Marionette nested Collection templating - node.js

all
I'm developing an application that store my multimedia catalog, I've JSON collection like this :
{ "_id" : ObjectId( "5142f55394474e2aac000001" ),
"contentType" : "binary/octet-stream",
"length" : 2732376,
"chunkSize" : 262144,
"uploadDate" : Date( 1363342677601 ),
"metadata" : {
"TIT2" : "Chase The Blues (Cameron McVey Remix)",
"TPE1" : "Terranova",
"TRCK" : "1/13",
"TALB" : "!K7",
"TPOS" : "1/1",
"TDRC" : "2000-06",
"TCON" : [
"Electronica",
"Trip-Hop" ],
"COMM" : [
"Chillout",
"Love",
"German",
"Berlin",
"2000s",
"Female Vocalists",
"Male Vocalists" ],
"TMED" : "CD",
"TMOO" : "Chill",
"TDOR" : "2000-06",
"TSO2" : "Various Artists",
"TPE2" : "Various Artists",
"TCMP" : "1",
"TSOP" : "Terranova",
"TIT1" : "Electronica",
"TPUB" : "Sinedín Music",
"TLAN" : "eng",
"TYER" : [
"2000" ],
},
"md5" : "617401af615ac0c6cb1dee9a3f1b99e6",
"origin" : "Chase The Blues.109eb5ab5105a1caa505a26657f7f9a8.mp3",
"evolution" : null,
"insertDate" : Date( 1336662308000 ),
"tagSource" : "MusicBrainz",
"mediainfo" :
{ "Format" : "MPEG Audio",
"Format version" : "Version 1",
"Format profile" : "Layer 3",
"Duration" : "3mn 47s",
"Bit rate mode" : "Constant",
"Bit rate" : "96.0 Kbps",
"Channel(s)" : "1 channel",
"Sampling rate" : "44.1 KHz",
"Compression mode" : "Lossy",
"Stream size" : "2.60 MiB (100%)",
"Language" : "English"
}
}
so, as you can see, there are "metadata" and "mediainfo" array in the document
in the models.js , in the client side, I've rewrite the model parse function like this
var Audio_Model = Backbone.Model.extend({
idAttribute: "_id",
url: 'AudioModel',
urlRoot: 'AudioModel' ,
parse: function(response) {
// Check if response includes some nested collection data...
if (_.has(response, 'metadata')){
// Check if this model has a property called metadata
if (!_.has(this, 'metadata')) { // It does not...
// So instantiate a collection and pass in raw data
this.metadata = new Audio_Collection_Metadata(response.metadata);
} else {
// It does, so just reset the collection
this.metadata.reset(response.metadata);
}
delete response.metadata;
}
// Check if response includes some nested collection data...
if (_.has(response, 'mediainfo')){
// Check if this model has a property called mediainfo
if (!_.has(this, 'mediainfo')) { // It does not...
// So instantiate a collection and pass in raw data
this.mediainfo = new Audio_Collection_Mediainfo(response.mediainfo);
} else {
// It does, so just reset the collection
this.mediainfo.reset(response.mediainfo);
}
delete response.mediainfo;
}
return response;
}
});
so I've created two separate collection of 'metadata' and 'mediainfo'
the problem that I've is how to render 'metadata' and 'mediainfo' in html template because in 'mediainfo' and 'metadata' collection the key, values are not fixed and in 'metadata' some keys are array of values and the number of item in the array are not fixed
I've created backbone.marionette.itemview and compositeview for these two collections but I don't know how to render
Plase, someone have a solutions ?
Best Regards

finally I've fixed the problem myself with a data normalization, this is the new mongoose schema adopted :
var TagSchema = new mongoose.Schema({
value : {type : String, default: '', required: true}
});
var MetadataSchema = new mongoose.Schema({
name : {type: String, default: '', required : true},
values: [TagSchema]
});
var MediainfoSchema = new mongoose.Schema({
name : {type: String, default: ''},
value: {type: String, default: ''}
});
var StreamSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
TIT2: {type : String, default: '', required: true},
metadata: [MetadataSchema],
mediainfo:[MediainfoSchema]
});
so that with sequence of CollectionView and CompositeView I can browse the entire model
Hope this can help someone

Related

MongoDB query on join

This is an abstract example, but if someone can help me to solve it, I will be eternally grateful.
I am trying to do a search based on a field in a related record. In this example we have a hierarchy of subjects, that are nested using the parent_subject field. This is the Mongoose definition I have used:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var subjectSchema = new Schema({
url: { type: String, required: true, unique: true },
title: { type: String, required: true, unique: true },
parent_subject: this
});
module.exports = mongoose.model('Subject', subjectSchema);
Some records in my MongoDB:
{
"_id" : ObjectId("5a3857f1afeb498c9533aef1"),
"title" : "Sport",
"url" : "sport",
"__v" : 0
},
{
"_id" : ObjectId("5a3d9a409c0973976f7889c6"),
"title" : "Cycling",
"__v" : 0,
"parent_subject" : ObjectId("5a3857f1afeb498c9533aef1"),
"url" : "cycling"
},
{
"_id" : ObjectId("5a3d9a7e9c0973976f788b48"),
"title" : "Mountain Biking",
"__v" : 0,
"parent_subject" : ObjectId("5a3d9a409c0973976f7889c6"),
"url" : "mountain biking"
}
I would like to know how I can query this data based on a field in the parent record. For example, I would like to find all the subjects that have a parent subject with the title "Sport". In SQL, I would do the following query:
SELECT *
FROM subject
INNER JOIN subject AS parentSubject
ON subject.parent_subject = parentSubject.id
WHERE parentSubject.title = "Sport";
How would I achieve this with a MongoDB?
You can use mongodb aggregate pipeline and lookup for this
`Subject.aggregate([
{
$lookup:
{
from: "parentSubject",
localField: "parent_subject",
foreignField: "id"
as: "parentSubject"
}
},
{$unwind:"$parentSubject"},
{$match:{"$parentSubject.title":"Sport"}}
])`
For more reference you can see https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/index.html
The point of mongoDB is that it is NOSQl, so that you also cannot use joins.
Your best option would be to first acquire the parentSubject and it's id.
And afterwards go for the subjects related to that id.
Since your data already has a subject.parent_subject it should be pretty easy to do.

Add key value pair data

I have a schema in Mongoose that looks like this:
const SocketDetailsUserSchema = new mongoose.Schema({
userId: String,
socketValue: [{
id: String,
data : String
}],
isDeleted: Boolean,
dateCreated: Date,
updateAt: Date
});
I want to insert data of socketValue in key value pair in array format. Which should look like ,
{
"_id" : ObjectId("5a12809c7f7afb1e3626857f"),
"userId" : "59eee19696fe6560cd54a081",
"socketValue" : [{"id":"5a05855b10600e4aa5b3a48e" , "value" : "123" }],[{"id":"5a0ae037a90746c249b6c1f7" , "value" : "456" }],
"isDeleted" : false
"__v" : 0
}
This is the mongoose data format.
How can i insert data in mongoose like this ?
I am also confused that how should i post data from postman to insert data in this ?
I think your current structure is good just add _id: false to avoid to add auto generated _id in socketValue. like
socketValue: [{
id: String,
data : String,
_id: false
}],
for this structure data will store like:
"socketValue" : [{"id":"5a05855b10600e4aa5b3a48e" , "value" : "123" },{"id":"5a0ae037a90746c249b6c1f7" , "value" : "456" }]"
then you can easily update or add new socketValue. I think this [{..},{..},{..}] is the better structure instead of [[{..}][{..}]] this structure.
and for this structure postman request body should contain like.
{
"userId" : "59eee19696fe6560cd54a081",
"socketValue" : [{"id":"5a05855b10600e4aa5b3a48e" , "value" : "123" },{"id":"5a0ae037a90746c249b6c1f7" , "value" : "456" }]",
"isDeleted" : false
}
and in your server side code just use like
var newSocket = new Socket(req.body); // assume your model name is Socket
newSocket.save();
Your postman input data should be raw json format
{
"userId" : "59eee19696fe6560cd54a081",
"socketValue" : [{"id":"5a05855b10600e4aa5b3a48e" , "value" : "123" },{"id":"5a0ae037a90746c249b6c1f7" , "value" : "456" }]",
"isDeleted" : false
}
Your server code
var insertDoc = new collectionname(details);
inserDoc.save(function (err) {
if (err) {
//callback err
} else {
//callback result
}
});

Get Reference in a child object, where parent has array of children with mongoose in NodeJS

I'm working with mongoose in NodeJS and I have two main models, transactions and invoices, both could be inside a balance model, the models are defined like this:
const BalanceSchema = new Schema({
transactions: [{ type: Schema.Types.ObjectId, ref: 'Transaction'}],
invoices: [{ type: Schema.Types.ObjectId, ref: 'Invoice'}],
references: [filesDescription],
});
const TransactionSchema = new Schema({
paybook: PaybookTransaction,
});
I want to get all the transactions and know if they have a reference with Balance, The result that I except after make the consult:
[
{
_id: 'transaction_id'
paybook: {}
balance: 'balance_id'
}
]
Is this possible, or Do I need do this with js?
UPDATE 1
Example Data:
I Have Table Transaction with data:
{
"_id" : ObjectId("5988b1f62442837f5b8b911d"),
"updatedAt" : ISODate("2017-08-09T19:47:14.657Z"),
"createdAt" : ISODate("2017-08-09T19:47:14.657Z"),
"paybook" : {
"id_account" : "59763bc0244283dd798b4a57",
"id_account_type" : "520d3aa93b8e778e0d000000",
"id_credential" : "597a2fda0c212aa7648b58d3",
},
}
And the table Balance with data like:
{
"_id" : ObjectId("598ba359ff32954ffb22da5a"),
"updatedAt" : ISODate("2017-08-10T01:43:31.668Z"),
"createdAt" : ISODate("2017-08-10T00:05:45.491Z"),
"references" : [],
"invoices" : [],
"transactions" : [
ObjectId("5988b1f62442837f5b8b911d")
]
}
I want to get all the Transactions that have a reference in Balance. Like I show you in the json reference.

Mongoose $in not working in nodeJS

I've created a collection containing some operation details like below
{ "_id" : ObjectId("580776455ecd3b4352705ec4"), "operation_number" : 10, "operation_description" : "SHEARING", "machine" : "GAS CUTT" }
{ "_id" : ObjectId("580776455ecd3b4352705ec5"), "operation_number" : 50, "operation_description" : "EYE ROLLING -1", "machine" : "E-ROLL-1" }
{ "_id" : ObjectId("580776455ecd3b4352705ec6"), "operation_number" : 60, "operation_description" : "EYE ROLLING -2", "machine" : "E-ROLL-1" }
{ "_id" : ObjectId("580776455ecd3b4352705ec7"), "operation_number" : 70, "operation_description" : "EYE REAMING", "machine" : "E-REAM" }
{ "_id" : ObjectId("580776455ecd3b4352705ec8"), "operation_number" : 80, "operation_description" : "COLD CENTER HOLE PUNCHING", "machine" : "C-PNCH-1" }
{ "_id" : ObjectId("580776455ecd3b4352705ec9"), "operation_number" : 150, "operation_description" : "READY FOR HT", "machine" : "RHT" }
using mongoose model as below
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var Promise = require("bluebird");
mongoose.Promise = Promise;
var Schema = mongoose.Schema;
var operationSchema = new Schema({
operation_number: {
type: String,
required: [
true,
"Please select valid operation code"
]unique : true
},
operation_description: {
type: String,
required: [
true,
"Please select valid operation description"
]
}
}, { strict: false });
var operation = mongoose.model('operation', operationSchema);
operationSchema.plugin(uniqueValidator, { message: 'Error, {PATH} {VALUE} already exist.' });
// make this available to our users in our Node applications
module.exports = operation;
now if I query this collection operations using db.operations.find({operation_number : {$in : [10, 50, 60]}}) it works but when it comes to mongoose it's not working.
var mc = require("./data-models/operation")
var filter = {'operation_number':
{$in :
[10, 50, 60]
}
}
console.log(filter)
mc.find(filter, function(me, md){
console.log(me, md) // prints null []
})
Even I've tried removing single quotes around operation_number
Please help finding way !
Your schema says that operation_number is a string:
operation_number: {
type: String, <-- here
...
}
Therefore, Mongoose will cast the numbers in the $in array to strings.
However, the data in the database is numerical, which is a different type. You should change your schema so that operation_number becomes a Number:
operation_number: {
type: Number,
...
}
Sometimes it happens that you forget to define that attribute in the schema.

error when trying to save geojson object using mongoosejs

If I have the following schema:
var zipSchema = new mongoose.Schema({
zc_code : String,
zc_population : Number,
zc_households : Number,
zc_housevalue : Number,
zc_householdincome : Number,
zc_statecode : String,
zc_state : String,
zc_city : String,
zc_cityname : String,
modified_at : Date,
center: {
type: {type: String},
coordinates: []
}
})
zipSchema.index({ center: '2dsphere' });
And the I try this:
var zipInfo = {
zc_code: '78746',
zc_population: 26928,
zc_households: 10839,
zc_housevalue: 344000,
zc_householdincome: 100571,
zc_latitude: '30.295657',
zc_long: '-97.813727',
zc_statecode: 'TX',
zc_state: 'Texas',
zc_city: 'AUSTIN',
center: {
coordinates: [-73.7567, 42.6525],
type: 'Point'
}
}
Zip.create(zipInfo, function(err) { if (err) console.log(err) })
I get this error every time:
MongoError: location object expected, location array not in correct format
What am I missing. I have searched stackoverflow and seen several different setups for the geojson stuff. I even tried directly copying some stuff from mongoosejs tests and still get errors. I am at a dead end. Any help would be appreciated
It didn't work for me either but I have just fixed it by naming the geometry field: "loc" like here: http://docs.mongodb.org/manual/core/2dsphere/
Here the example I used:
var cableSchema = new mongoose.Schema({
reference: String,
owner: String,
status: String,
setup: String,
model: Number,
loc: {
type: {type:String},
coordinates: Array
}
});
I tried the following with the latest mongoose and it did work for me. Which version are you using? And as for the { type: {type: String } } question, I believe it is because type is also a mongoose keyword type:
var zipSchema = new mongoose.Schema({
zc_code : String,
zc_population : Number,
zc_households : Number,
zc_housevalue : Number,
zc_householdincome : Number,
zc_statecode : String,
zc_state : String,
zc_city : String,
zc_cityname : String,
modified_at : Date,
center: {
type: {type:String},
coordinates: [Number]
}
})
zipSchema.index({ center: '2dsphere' });
var zipInfo = {
zc_code: '78746',
zc_population: 26928,
zc_households: 10839,
zc_housevalue: 344000,
zc_householdincome: 100571,
zc_latitude: '30.295657',
zc_long: '-97.813727',
zc_statecode: 'TX',
zc_state: 'Texas',
zc_city: 'AUSTIN',
center: {
type: 'Point',
coordinates: [-73.7567, 42.6525]
}
}
var Zip = mongoose.model('Zip', zipSchema);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
Zip.create(zipInfo, function(err) {
if (err) console.log(err);
mongoose.disconnect();
})
});
The result was:
> db.zips.find().pretty()
{
"zc_code" : "78746",
"zc_population" : 26928,
"zc_households" : 10839,
"zc_housevalue" : 344000,
"zc_householdincome" : 100571,
"zc_statecode" : "TX",
"zc_state" : "Texas",
"zc_city" : "AUSTIN",
"_id" : ObjectId("522e2df92aacd22e89000001"),
"center" : {
"type" : "Point",
"coordinates" : [
-73.7567,
42.6525
]
},
"__v" : 0
}
> db.zips.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.zips",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"center" : "2dsphere"
},
"ns" : "test.zips",
"name" : "center_2dsphere",
"background" : true,
"safe" : null
}
]
>

Resources