My data is stored in a table "mysettings" in DynamoDB with the following schema : "pk" as hash key and "sk" as range key
Example data item:
{
"mSettings": {
"gflag": true,
"name": "green",
"type": "B"
},
"pk": "Group1",
"sk": "A1000",
"xSettings": {
"gflag": false,
"name": "blue",
"type": "A"
},
"ySettings": {
"gflag": false,
"name": "green",
"type": "B"
},
"zSettings": {
"gflag": true,
"name": "red",
"type": "A"
}
}
Now, here I am trying to fetch(filter) only those settings where my gflag field is true.
Like for above example item, it should return only "mSettings" & "zSettings" nodes.
Below is my tried sample code:
var AWS = require('aws-sdk');
let region = "us-east-1";
AWS.config.region = region;
var docClient = new AWS.DynamoDB.DocumentClient();
let settingsItem = ["mSettings", "xSettings", "ySettings", "zSettings"];
let params = {
TableName: "mysettings",
KeyConditionExpression: "#pk = :pk AND #sk = :sk",
ExpressionAttributeNames:{
"#pk": "pk",
"#sk": "sk"
},
// FilterExpression : "ySettings.gflag = :gflag",
ExpressionAttributeValues: {
":pk": 'Group1',
":sk": 'A1000',
":gflag" : true
}
};
//for(let settings in settingsItem){
// params['FilterExpression'] = settingsItem[settings] + ".gflag = :gflag";
//}
console.log('params = ', params)
docClient.query(params, function(err, data){
if(err){
console.log(err)
}
console.log('data = ', data)
})
Kindly suggest to retrieve only those objects where flag value is true.
DynamoDB filters operate at an item level. They determine whether or not an item is returned to you. They can't be used to control which groups of attributes are returned to you. You can easily do that client-side with the query results.
Here's an example of post-processing the query results object to remove the sub-objects where gflag is not true:
const _ = require('lodash');
function gflag_true(value, key) {
return _.isObject(value) && value.gflag;
}
const item = {
"mSettings": { "gflag": true, "name": "green", "type": "B" },
"pk": "Group1",
"sk": "A1000",
"xSettings": { "gflag": false, "name": "blue", "type": "A" },
"ySettings": { "gflag": false, "name": "green", "type": "B" },
"zSettings": { "gflag": true, "name": "red", "type": "A" }
}
// transform item returned from DocumentClient query method
const rc = _.pickBy(item, gflag_true)
This results in:
{
mSettings: { gflag: true, name: 'green', type: 'B' },
zSettings: { gflag: true, name: 'red', type: 'A' }
}
The objective is to show a filtered list of items for each possible state. I'm trying a template because such a list may need to display in many places. The template calls filterItems to get its particular list of items.
The filterItems code below uses a field in the viewModel (current_filter), so all the lists have the same items (3 and 8 which are in a ready state) :( That's not the idea. Each template instance has $data which contains the correct filter value. Is there a way to make this filter value available to the filterItems function?
<script>
var viewModel = {
items: ko.observableArray(
[
{ "iid": 1, "state": "entered" },
{ "iid": 3, "state": "ready" },
{ "iid": 4, "state": "delivered" },
{ "iid": 8, "state": "ready" },
{ "iid": 13, "state": "entered" }
]),
states: ko.observableArray(
[
{ "sid": 1, "filter": "entered", "color": "yellow" },
{ "sid": 2, "filter": "ready", "color": "red" },
{ "sid": 3, "filter": "delivered", "color": "blue" }
]),
current_filter: 'ready'
}
viewModel.filterItems = ko.computed(function () {
var filtered_items = [];
for (var i = 0; i < viewModel.items().length; ++i)
if(viewModel.items()[i].state == viewModel.current_filter)
filtered_items.push(viewModel.items()[i]);
return filtered_items;
}, viewModel);
</script>
<div data-bind="foreach: states">
<div data-bind="template: {name: 'state', data: $data}"></div>
<script type="text/html" id="state">
<h2 data-bind="text: filter"></h2>
<ul data-bind="foreach:viewModel.filterItems()">
<li>
<div data-bind="text: iid"></div>
</li>
</ul>
</script>
</div>
<script>ko.applyBindings(viewModel);</script>
jsFiddle at https://jsfiddle.net/mthrock/kxpfdfva/8/#&togetherjs=JKJOos6VJc
how about a component instead of a template?
run snippet below
ko.components.register('mycomponent', {
viewModel: function(params) {
var self = this;
this.items = ko.observableArray(
[{
"iid": 1,
"state": "entered"
}, {
"iid": 3,
"state": "ready"
}, {
"iid": 4,
"state": "delivered"
}, {
"iid": 8,
"state": "ready"
}, {
"iid": 13,
"state": "entered"
}]);
this.filter = params.filter;
this.filterItems = ko.computed(function() {
var filtered_items = [];
for (var i = 0; i < this.items().length; ++i)
if (this.items()[i].state == this.filter)
filtered_items.push(this.items()[i]);
return filtered_items;
}, this);
},
template: ' <h2 data-bind="text: filter"></h2>\
<ul data-bind="foreach:filterItems()">\
<li>\
<div data-bind="text: iid"></div>\
</li>\
</ul>'
});
function model() {
var self = this;
this.states = ko.observableArray(
[{
"sid": 1,
"filter": "entered",
"color": "yellow"
}, {
"sid": 2,
"filter": "ready",
"color": "red"
}, {
"sid": 3,
"filter": "delivered",
"color": "blue"
}]);
}
var mymodel = new model();
$(document).ready(function() {
ko.applyBindings(mymodel);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-bind="foreach: states">
<mycomponent params="filter: filter"></mycomponent>
</div>
sample document :
{"name":"John", "age":35, "address":".....",.....}
Employees whose join_month=3 is priority 1
Employees whose address contains the string "Avenue" is priority 2
Employees whose address contains the string "Street" is priority 3
Employees whose address contains the string "Road" is priority 4
As of now, I'm at this stage:
db.collection.aggregate([
{ "$match": {
"$or": [
{ "join_month": 3 },
{ "address": /.*Avenue.*/i },
{ "address": /.*Street.*/i },
{ "address": /.*Road.*/i }
]
}},
{ "$project": {
"name": 1,
"age": 1,
"_id": 0,
"priority": { ?????????? }
}},
{ "$sort": { "priority": 1 } }
])
I'm stuck at priority field. What should I put there?
Using the aggregation framework you would "ideally" want to use the $regex filter within the $cond logical operator in the $project pipeline step but unfortunately MongoDB is yet to support this.
There is a JIRA ticket for this currently open $project filter using $regex
However, a workaround (though not the best solution performant-wise) would be to use map-reduce. Consider populating a test collection:
db.test.insert([
{ _id: 0, "join_month": 12, "address": "33 Point Avenue", "name": "John", "age":35 },
{ _id: 1, "join_month": 10, "address": "2A Broad Street, Surbub", "name": "Jane", "age":21 },
{ _id: 2, "join_month": 3, "address": "127 Umpstreeten Road, Surbub", "name": "Alan", "age":63 },
{ _id: 3, "join_month": 3, "address": "127 Umpstreeten Road, Surbub", "name": "Louise", "age":30 }
])
Define your map function as:
var mapper = function() {
var priority;
if (this.join_month==3){
priority = 1;
}
else if (this.address.match(/Avenue/i)){
priority = 2;
}
else if (this.address.match(/Street/i)){
priority = 3;
}
else if (this.address.match(/Road/i)){
priority = 4;
}
else {
priority = 99;
}
var value = {
"name": this.name,
"age": this.age,
"priority": priority
};
emit( this._id, value );
};
The reduce function follows:
var reducer = function() { };
Then run the mapduce operation on the test collection and store the result in the collection mr_result
db.test.mapReduce(mapper, reducer, {
"out": 'mr_result'
"query": {
"$or": [
{ "join_month": 3 },
{ "address": /.*Avenue.*/i },
{ "address": /.*Street.*/i },
{ "address": /.*Road.*/i }
]
}
})
Query the result collection:
db.mr_result.find().sort({ "priority": 1})
Sample Output
{ "_id" : 2, "value" : { "name" : "Alan", "age" : 63, "priority" : 1 } }
{ "_id" : 3, "value" : { "name" : "Louise", "age" : 30, "priority" : 1 } }
{ "_id" : 0, "value" : { "name" : "John", "age" : 35, "priority" : 2 } }
{ "_id" : 1, "value" : { "name" : "Jane", "age" : 21, "priority" : 3 } }
I am using the Kendo TreeList. I have a data structure in the database using an Adjacency List data structure using Django TreeBeard. For the treelist, since the data is nested, I create flat objects and put them into an array. This works, fine but the treelist doesn't refresh with the data.
The object structure is the same as the one for the parent but the children don't show.
Here is my code.
JSON: PARENT NODE
{"id": 26, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 8, "parent": null, "SSM": {"id": 8, "securitySelectionModelName": "ssm8", "userCreatedModel": "[{\"classificationName\":\"ssm8\",\"id\":8,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"MBS\",\"id\":14,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"Common Stock\",\"id\":15,\"hasChildNode\":false}]}]}]", "classificationNames": []}, "classificationNameNode": null}
JSON CHILD NODE
[{"id": 27, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 14, "parent": {"id": 26, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 8, "parent": null, "SSM": 8, "classificationNameNode": null}, "SSM": {"id": 8, "securitySelectionModelName": "ssm8", "userCreatedModel": "[{\"classificationName\":\"ssm8\",\"id\":8,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"MBS\",\"id\":14,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"Common Stock\",\"id\":15,\"hasChildNode\":false}]}]}]", "classificationNames": []}, "classificationNameNode": {"id": 14, "classificationLevel": 2, "classificationName": "MBS", "hasChildNode": false, "parent": 2}}]
JAVASCRIPT
$(document).ready(function () {
var id = {{ id }};
var dataSource = new kendo.data.TreeListDataSource({
transport: {
read: {
url: "../getModelTargetWeights?SSM_id="+id,
dataType: "json"
}
},
schema: {
parse: function(response) {
NodeArray=[];
if (response.length == undefined) {
var node = {
id: response.id,
currWeight: response.currWeight,
tgtWeight: response.tgtWeight,
hasChildren: response.hasChildnode,
parentId: response.parent,
ext_model_id: response.ext_model_id,
securitySelectionModelName: response.SSM.securitySelectionModelName,
classificationNameNode: response.classificationNameNode
};
NodeArray.push(node);
} else {
for (var i=0; i < response.length; i++){
var node = {
id: response[i].id,
currWeight: response[i].currWeight,
tgtWeight: response[i].tgtWeight,
hasChildren: response[i].hasChildnode,
parentId: response[i].parent.ext_model_id,
ext_model_id: response[i].ext_model_id,
securitySelectionModelName: response[i].SSM.securitySelectionModelName,
classificationNameNode: response[i].classificationNameNode.classificationName
}
NodeArray.push(node);
}
}
return NodeArray;
},
model: {
id: "id",
parentId: "parentId",
fields: {
parentId: { field: "parentId", nullable: true },
securitySelectionModelName: "securitySelectionModelName",
classificationNameNode: "classificationNameNode",
tgtWeight: { field: "tgtWeight", nullable: true },
hasChildren: { type: "boolean", field: "hasChildren" }
}
}
}
});
$("#treeList").kendoTreeList({
dataSource: dataSource,
editable: true,
height: 540,
columns: [
{ field: "securitySelectionModelName", title: "Model Name" },
{ field: "classificationNameNode", title: "Classification" },
{ field: "tgtWeight", title: "Target" }
],
});
dataSource.read();
});
</script>
I'm working on an API for a school platform.
I want to migrate and seed the database in a boot script, while I'm still developing.
I can make school instances, group instances, and person instances, but I cannot figure out how to add a relation between the person instances and the group instances (Many to Many)
This is my Person .json file:
{
"name": "Person",
"base": "User",
"strict": true,
"idInjection": true,
"properties": {
"name": {
"type": "string",
"required": true
},
"firstName": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"groups": {
"type": "hasAndBelongsToMany",
"model": "Group"
},
"school": {
"type": "belongsTo",
"model": "School"
}
},
"acls": [],
"methods": []
}
This is my group.json file
{
"name": "Group",
"base": "PersistedModel",
"strict": true,
"idInjection": true,
"properties": {
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"people": {
"type": "hasAndBelongsToMany",
"model": "Person"
},
"school": {
"type": "belongsTo",
"model": "School"
}
},
"acls": [],
"methods": []
}
And this is my boot script:
var async = require('async');
module.exports = function(app) {
var mysqlDs = app.dataSources.mysqlDs;
var boysNames = ["Lucas", "Liam", "Arthur", "Vince", "Noah", "Finn", "Mathis", "Louis", "Adam", "Jules", "Lars", "Seppe", "Stan", "Alexander", "Leon", "Kobe", "Victor", "Matteo", "Milan", "Mats", "Vic", "Wout", "Daan", "Senne", "Ferre", "Tuur", "Nathan", "Elias", "Warre", "Jack", "Felix", "Cas", "Thomas", "Lowie", "Robbe", "Lewis", "Rayan", "Nand", "Sem", "Maxim", "Emiel", "Jasper", "Oscar", "Mauro", "Sam", "Mohamed", "Luca", "Bent", "Ruben", "Simon", "Imran", "Jayden", "Lou", "Viktor", "Bas", "Lenn", "Rune", "Lukas", "Eden", "Emile"];
var girlsNames = ["Emma", "Louise", "Elise", "Ella", "Marie", "Noor", "Lena", "Julie", "Lotte", "Olivia", "Anna", "Elena", "Mila", "Lore", "Fien", "Nina", "Lina", "Nora", "Laura", "Juliette", "Charlotte", "Lisa", "Amber", "Amélie", "Fleur", "Renée", "Lily", "Sara", "Camille", "Hanne", "Luna", "Liv", "Roos", "Helena", "Sarah", "Sofia", "Janne", "Noa", "Jade", "Nore", "Fenna", "Axelle", "Kato", "Alice", "Aya", "Jana", "Lize", "Paulien", "Amelie", "Lucie", "Lara", "Zoë", "Mona", "Manon", "Leonie", "Ines", "Oona", "Laure", "Mira", "Febe"];
var names = ["Jong","Jansen","Vries","Visser","Jans","Bakker","Dijk","Vos","Smit","Berg","Boer","Groot","Janssen","Jacobs","Veen","Bos","Bergman","Hendriks","Dekker","Mulder","Willems","Meijer","Graaf","Leeuwen","Vermeulen","Koster","Peeters","Brouwer","Kok","Peters","Smits","Linden","Vliet","Wit","Beekman","Bosch","Meer","Koning","Beek","Haan","Vermeer","Verhoeven","Bruijn","Jonge","Heuvel","Martens","Dam","Hoek","Pieters","Walle","Bruin","Timmermans","Prins","Wouters","Janssens","Blom","Velde","Loon","Lange","Maas","Mol","Dijkstra","Post","Wal","Maes","Dieleman","Hermans","Jager","Stam","Gerrits","Groen","Roos","Wijk","Kuiper","Broek","Leeuw","Lambert","Kroon","Verdonck","Geerts","Boon","Hoekstra","Schouten","Gastel","Brink","Goossens","Steen","Bleijenberg","Bijl","Dubois","Jonker","Rooij","Driel","Pol","Ruiter","Stevens","Horst","Verbeek","Mertens","Ende","Sanders","Driessen","Huisman","Kooij","Schipper","Waal","Laan","Scholten","Vink","Ven","Postma","Aerts","Santen","Roovers","Verhulst","Verschoor","Ham","Moerman","Rijn","Bax","Franken","Eijk","Martin","Bosman","Meulen","Veenstra","Mostert","Velden","Harms","Wolters","Zanten","Claes","Poot","Ridder","Ginkel","Doorn","Heijden","Oost","Os","Blok","Kramer","Simons","Kuipers","Rovers","Cornelis","Dupont","Valk","Zwart","Gerard","Verweij"]
//first lets recreate all databases
mysqlDs.automigrate(function(){
console.log("tables recreated: let's seed");
async.parallel({
schools: async.apply(createSchools)
// ....
}, function(errFase1, resultsFase1) {
if (errFase1) throw errFase1;
async.parallel({
groups: async.apply(createGroups, resultsFase1.schools),
persons: async.apply(createStudents, resultsFase1.schools),
}, function(errFase2, resultsFase2) {
if (errFase2) throw errFase2;
// ???????????????????????????????????
// ??? HOW TO add a relation between the persons and the groups
// a person must be able to live
// in multiple groups
});
});
});
function createSchools(cb) {
var School = app.models.School;
School.create([
{
"name": "Harvard",
"address": "xxx",
"zip": "0000",
"place": "yyy"
},
{
"name": "Oxford",
"address": "xxx",
"zip": "0000",
"place": "yyy"
}
], cb);
}
function createGroups(schools,cb) {
var Group = app.models.Group;
Group.create([
{ "name": "Class 1", "schoolId": schools[0].id },
{ "name": "Class 2", "schoolId": schools[0].id },
{ "name": "Class 3", "schoolId": schools[0].id },
{ "name": "Class 4", "schoolId": schools[0].id },
{ "name": "Class 5", "schoolId": schools[0].id },
{ "name": "Class 6", "schoolId": schools[0].id },
{ "name": "Class 1", "schoolId": schools[1].id },
{ "name": "Class 2", "schoolId": schools[1].id },
{ "name": "Class 3", "schoolId": schools[1].id },
{ "name": "Class 4", "schoolId": schools[1].id },
{ "name": "Class 5", "schoolId": schools[1].id },
{ "name": "Class 6", "schoolId": schools[1].id },
], cb);
}
function createStudents(schools,cb) {
var Person = app.models.Person;
var students = [];
for (var i = 0; i < 240; i++) {
chooseFrom = (i%2 == 1) ? girlsNames : boysNames ;
students.push({
"name": names[i%names.length],
"firstName": chooseFrom[i%chooseFrom.length],
"username": "student"+i,
"password": "testje",
"email": "student"+i+"#mailinator.com",
"emailVerified": true,
"schoolId": schools[Math.floor(i/120)].id
});
};
Person.create(students, cb);
}
};
To add students to groups, I expected something like this, would do the trick :
Group.findOne(function(err, group){
console.log(group);
group.people().add(students[0].id);
})
I can't find any tutorials on this specific question.
I debugged the bootscript, and inspected the group variable, it's a ModelConstructor. I'm guessing I can get the related people via the people() function, but how can I add a person to a specific group?
Found the correct docs on this one:
http://apidocs.strongloop.com/loopback-datasource-juggler/#relationmixin-hasandbelongstomany
// id needs to be passed not entire instance. even loopbackjs docs needs to be updated
var student = students[0];
Group.findOne(function(err, group){
console.log(group);
group.people.add(student.id); // <--- id and not instance
})