Partial account from MongoDB via NodeJS - javascript

Upon viewing the Mongo Count docs, it showed the following code :
// Peform a partial account where b=1
collection.count({b:1}, function(err, count) {
where it count every document that has b:1. Those documents can look something like this
{
a:1,
b:1,
c:1
}
How can I find the partial account on a more in-depth level. For example consider the following document. How can I count every document that contains
"Name": "LOG-11-05-SH-O1.mp4" ?
"display": {
"0": {
"Name": "LOG-11-05-SH-O1.mp4",
"Type": "Startup",
"Count": "2",
"Detail": {
"0": {
"Start": "2013-01-20,11:32:22",
"End": "2013-01-20,11:32:30"
},
"1": {
"Start": "2013-01-20,11:32:22",
"End": "2013-01-20,11:32:30"
}
}
},
"1": { ....
I know that "display.0.Name" : "LOG-11-05-SH-O1.mp4" will count everytime "LOG-11-05-SH-O1.mp4" appears under display 0, but sometimes the number may change. For example, next time time "LOG-11-05-SH-O1.mp4" might be under display 1. Thus is there a way to perform a count on only "LOG-11-05-SH-O1.mp4" or perhaps ignore the middle number?

See my comments on your question, but I don't see a way to do this without using an array instead of an object for the value of display. If it is an array, this becomes trivial.
Suppose your data looked like this:
"display": {[
{
"Name": "LOG-11-05-SH-O1.mp4",
"Type": "Startup",
"Count": "2",
"Detail": {
"0": {
"Start": "2013-01-20,11:32:22",
"End": "2013-01-20,11:32:30"
},
"1": {
"Start": "2013-01-20,11:32:22",
"End": "2013-01-20,11:32:30"
}
}
, { ....}
]}
Then you query would just be:
db.foos.count({"display": {$elemMatch: { "Name" : "LOG-11-05-SH-O1.mp4"}}})
Here is the relevant MongoDB page on $elemMatch: http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/.
If you must keep the object schema, then you can grab all the records and do the count on the app side and not in MongoDB.
If someone else knows a way to pull this off without the array, I'm happy to receive a downvote and then just remove what would then be an incorrect answer.

I feel kind of silly not realizing this at first. The answer is quite simple:
"display.Name": "LOG-11-05-SH-O1.mp4"
This will find all entries under display that has that following name.

Related

sails.js update or add new row

I'm starting a project using sails.js and I'ma bit confused about something.
I have a structure like this
[
{
"logins": {
"1": {
"login time": "2016-04-02T11:40:06.731Z"
}
}
"username": "test",
"password": "test",
"createdAt": "2016-04-02T11:40:06.731Z",
"updatedAt": "2016-04-02T11:40:06.731Z",
"id": "56ffaf9692bcf108169ef7c8"
}
]
now when a user logs in again, ideally I want the data to look like this
[
{
"logins": {
"1": {
"login time": "2016-04-01T11:40:06.731Z"
},
"2": {
"login time": "2016-04-02T11:40:06.731Z"
}
}
"username": "test",
"password": "test",
"createdAt": "2016-04-01T11:40:06.731Z",
"updatedAt": "2016-04-01T11:40:06.731Z",
"id": "56ffaf9692bcf108169ef7c8"
}
]
However, I cannot for the live of me figure out how to "update" or "insert" a new row under "logins" for my user.
Creating the first record is fine and so far the best I could come up with is reading the current value for logins into a buffer and then re-inserting all the values.
That seems clumsy. Does anyone know if sails has some built in method to support what I'm trying to achieve?
I would change your 'Logins' argument to array. Than you can use $push while updating. Waterline support only $set operation, so if you want to do that you need to use .native() like that:
Model.native(function(error,collection){
collection.update(
{_id:YOURID}, // where condition
{$push:{logins:new Date()}}, // push new value to array
{}, // options
function(error,result){} // callback
)
})
To see what you can do with native, see Node.js MongoDB Driver API - Collections

Mongodb find in hash by value

i have this mongodb documents format:
{
"_id": ObjectId("5406e4c49b324869198b456a"),
"phones": {
"12035508684": 1,
"13399874497": 0,
"15148399728": 1,
"18721839971": 1,
"98311321109": -1,
}
}
phones field - its a hash of phone numbers and frequency of its using.
And i need to select all documents, which have at least one zero or less frequency.
Trying this:
db.my_collection.find({"phones": { $lte: 0} })
but no luck.
Thanks in advance for your advices
You can't do that sort of query in MongoDB, well not in a simple way anyhow, as what you are doing here is generally an "anti-pattern", where part of your data is actually being specified as "keys". So a better way to model this is you use something where that "data" is actually a value to a key, and not the other way around:
{
"_id": ObjectId("5406e4c49b324869198b456a"),
"phones": [
{ "number": "12035508684", "value": 1 },
{ "number": "13399874497", "value": 0 },
{ "number": "15148399728", "value": 1 },
{ "number": "18721839971", "value": 1 },
{ "number": "98311321109", "value": -1 },
}
}
Then your query is quite simple:
db.collection.find({ "phones.value": { "$lte": 0 } })
But otherwise MongoDB cannot "natively" traverse the "keys" of an object/hash, and to do that you need do JavaScript evaluation to do this. Which is not a great idea for performance. Basically a $where query in short form:
db.collection.find(function() {
var phones = this.phones;
return Object.keys(phones).some(function(phone) {
return phones[phone] <= 0;
})
})
So the better option is to change the way you are modelling this and take advantage of the native operators. Otherwise most queries require and "explicit" path to any "key" inside the object/hash.

Populate AngularJS {{expression}} within ng-repeat using a second array

I'm completely rebuilding my website (originally hacked together with Wordpress) using Laravel and AngularJS. It's been a massive learning experience and I think I'm nearly there but for one problem.
On my site 'schemes' (or courses) are made up of 'units' which are made up of 'lessons'. Retrieving this data is fine, using Eloquent I retrieve valid JSON like this made up example...
[
{
"id": "1", //Scheme Id
"title": "Sports",
"description": "This is a Sports course!",
"units": [
{
"id": "1",
"title": "Tennis",
"lessons": [
{
"id": "6",
"title": "Serving"
},
{
"id": "7",
"title": "Hitting the ball with top-spin"
}
]
},
{
"id": "2",
"title": "Athletics",
"lessons": [
{
"id": "1",
"title": "Long Jump"
},
{
"id": "2",
"title": "Hurdling Technique"
}
]
},
{
"id": "4",
"title": "Golf",
"lessons": [
{
"id": "4",
"title": "Pitching"
},
{
"id": "5",
"title": "Putting"
}
]
}
]
}
....
]
Separately I have a simple array of completed lesson ids for a particular user like this...
[2, 6, 8, 9] ///User has completed lessons with ids of 2,6,8 and 9
In my view I'm using nested ng-repeat loops like so...
...
<div ng-controller="SchemesController">
<div ng-repeat="scheme in schemes">
<h1>{{scheme.title}}</h1>
<div ng-repeat="unit in scheme.units">
<h3>{{unit.title}}</h3>
<div ng-repeat="lesson in unit.lessons">
<div>{{lesson.title}}: {{status}}</div>
</div>
</div>
</div>
</div><!--[end of ng-controller="SchemesController"]-->
....
SchemesController (v simple!) looks like this...
var app = angular.module('schemesApp', []);
app.controller('SchemesController', function($scope){
$scope.schemes=jsonData;
});
The problem is I have no idea how to populate the {{status}} field which I want to state simply 'Complete' or 'Incomplete. I investigated whether I could somehow add this info to my original array like this...
"lessons": [
{
"id": "6",
"title": "Serving",
"status": "Complete" //populated somehow
},
{
"id": "7",
"title": "Hitting the ball with top-spin",
}
]
but I got nowhere slowly. Is there a way to do this (I've played around with underscore.js and felt this could help?).
Or do I populate {{status}} from creating and calling a javascript function?!?
ANY help that anyone could offer would be incredible. I'm a school teacher and for some sadistic reason I find a bit of programming/web design a fun use of my spare time so I apologise if this is a stupid question. THANKS in advance!!!
btw if anyone has a better 'title' for this question then please let me know.
I'm assuming you don't need to persist the status back to the database...
This is where you're having the problem:
<div>{{lesson.title}}: {{status}}</div>
You really don't need to store the status in your data model, because it's just used for presentation purposes.
Let's say your array of completed lessons is defined like this:
$scope.completedLessons = [1, 2, 3, 4, 5] // Or however you'd assign it
You need to create a function in your scope like this:
$scope.isLessonCompleted = function(lessonId) {
return $scope.completedLessons.indexOf(lessonId) > -1;
};
Then you need to change the html from above to this:
<div>{{lesson.title}}: {{isLessonCompleted(lesson.id) && 'Complete' || 'Incomplete'}}</div>
If lessons are also a model and each lesson should have a status, which isn't a column/field in your table but is something you'll add logic to determine, you could add a custom model accessor by adding the following to your models/Lesson.php:
// Append custom accessor attributes
protected $appends = ['status'];
public function getStatusAttribute() {
// Add logic here
return 'Complete';
}
This way, when you use Eloquent to retrieve your data, you'll also see a status attribute as part of the object, so you could then access it as usual $lesson->status (PHP) or lesson.status (JS).
For more information, see the official Laravel documentation on accessors and mutators

angular $watch over a particular field for all objects of an array

I have an array of halls like this, which I am getting from a $http.get().
$scope.halls = [
{
"_id": "524886d4c6d8a5a3b8949f6f",
"alias": "",
"hallId": "2",
"locationHint": "Near support team",
"name": "Conference Hall",
"bookQueue": [],
"occupancy": {
"occupied": true,
"occupiedBy": "Vignesh",
"purpose": "Sync up",
"team": "Edge",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"projector",
"Mac machine"
]
},
{
"_id": "524886fbc6d8a5a3b8949f70",
"alias": "",
"hallId": "3",
"locationHint": "Near Edge Team",
"name": "Training room",
"bookQueue": [],
"occupancy": {
"occupied": true,
"occupiedBy": "Tharma",
"purpose": "Review",
"team": "Platform",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"projector"
]
},
{
"_id": "52488794c6d8a5a3b8949f71",
"alias": "",
"hallId": "4",
"locationHint": "Near front office",
"name": "Front Office Discussion room",
"bookQueue": [],
"occupancy": {
"occupied": false,
"occupiedBy": "",
"purpose": "",
"team": "",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"TV"
]
}
]
I want to update the hall.occupancy, when the current date ( Date.now() )is greater than hall.occupancy.timeRange.to . In this case, I am not going to watch hall.occupancy.timeRange.to because, it is not the property that is going to change. Is there an angular way to do this, because it would get really messy to put a setInterval.
I am not really sure on how to go about this.
I am still in the early stages of learning angular, so it would be good if you were gentle in pointing out an efficient way.
I don't think that is something you can easily do. the $watch function watches a certain angular expression executed in the scope. You don't have a $scope.hall so it won't do anything. You could possibly watch each instance, but what if you add or remove items from the array?
$scope.$watch('halls[0].occupancy.timeRange.to', function(a, b) {
It would probably be better to just watch the halls array and loop through it to do your check on each item when anything changes. That is basically what angular does to detect changes itself.
$scope.watch('halls', function (newValue, oldValue) {
var now = Date.now();
for (var i = 0; i < newValue.length; i++) {
// check each item
}
};
You can sort your array by hall.occupancy.timeRange.to and execute setInvertal to the nearest upcoming date. Do the same again after timer event is fired taking the next item from sorted list.
If your list changes you have to cancel active timeout and set the new one using described procedure.
In my opinion $digest phase is not enough if you want to create notifications for inactive users - they leave the site with opened tab and do something else (I do that very often with Stackoverflow).
However if there is a lot of user events (clicks, playing with ng-model etc) in your application you should watch time and check the list after each 10 seconds:
var watchFn = function() {
var d = new Date();
return '' + d.getMinutes() + Math.floor(d.getSeconds()/10);
};
$scope.$watch(watchFn, function() {
console.log('User did something and $watch is fired after minimum 10s.');
});
Perhaps, I am doing this to solve this problem, but I am not sure if this is the best way.
setInterval(function(){
if($scope.halls)
{
for(var i =0 ;i< $scope.halls.length;i++){
var hall = $scope.halls[i];
if(hall.occupancy.timeRange.to){
if(Date.now() > new Date(hall.occupancy.timeRange.to.toString())){
//change occupancy.. either dequeue from blockQueue, shift to occupancy, or change occupancy.occupied to false
$scope.halls[i].occupancy = {occupied:false,occupiedBy:"",purpose:"",team:"",timeRange:{from:"",to:""}};
socket.emit('updateHall',$scope.halls[i]);
$scope.$apply();
}
}
}
}
},500);
So, basically, it checks every 500 milliseconds whether the current time is later than hall.occupancy.timeRange.to , if so, it resets the hall.occupancy field.
Let me know if you have a better solution.

Javascript looping through elements and adding to table

I'm having trouble finding a solution that will help me loop through a bunch of elements and putting the chosen values into a table. I've been able to withdraw some values but the method isn't dynamic.
Here is an example:
var Table = {
"credit": {
"link": "site link",
"logoUrl": "logo url",
"message": "message"
},
"groups": [
{
"labels": [
{
"name": "Western Conference",
"type": "conference"
},
{
"name": "Central Division",
"type": "division"
}
],
"standings": [
{
"stats": [
{
"name": "gp",
"value": 20
},
{
"name": "w",
"value": 17
},
{
"name": "l",
"value": 0
},
{
"name": "gf",
"value": 64
},
{
"name": "ga",
"value": 37
},
{
"name": "gd",
"value": 27
},
{
"name": "pts",
"value": 37
}
],
"team": {
"id": 12345,
"link": "team link",
"name": "team name",
"shortName": "team"
}
},
This is the structure of the elements. So far I've used this:
document.getElementById("sGamesPlayed").innerHTML=Table.groups[0].standings[0].stats[0].value;
to withdraw values. However there are more teams, stats and divisions so I would need some kind of loop to go through the elements and put the into a dynamic table.
I would consider you to look at http://underscorejs.org/.
it provides a bunch of utility functions that could help you,
for example, _.each() helps you loop through JSON properties.
for the sample objects you've given (after completing the missing brackets at the end),
_.each(Table.groups[0].standings[0].stats, function(stats){
console.log(stats['name']+","+stats['value'])
})
gives me:
gp,20
w,17
l,0
gf,64
ga,37
gd,27
pts,37
how it works is that you provide the object you want as the first argument and the function that you give as the second argument will be called with each element of the first argument (Assuming it is a list).
I would also urge you to look at underscore templating that you can use to render your table where i put the console.log :
http://net.tutsplus.com/tutorials/javascript-ajax/getting-cozy-with-underscore-js/
http://scriptble.com/2011/01/28/underscore-js-templates/
I guess your question is about filtering the values of the array standings. In order to do that you can use the jQuery grep function (if you want to use jQuery).
For example you can write:
var arr = $.grep(Table.groups[0].standings[0].stats, function(d){return d.value>25})
Which will give
arr = [{"name": "gf","value": 64}, {"name": "ga", "value": 37},{"name": "gd", "value": 27},{"name": "pts", "value": 37}]
If this is not what you meant, can you please create a jsFiddle with a sample of what you want?
Depending on what you want to do with the results, you can go over the object using a scheme like:
var groups, standings, stats, value;
groups = Table.groups;
// Do stuff with groups
for (var i=0, iLen=groups.length; i<iLen; i++) {
standings = groups[i].standings;
// Do stuff with standings
for (var j=0, jLen=standings.length; j<jLen; j++) {
stats = standings[j];
// Do stuff with stats
for (var k=0, kLen=stats.length; k<kLen; k++) {
value = stats[k].value;
// Do stuff with value
}
}
}
Of course I have no idea what the data is for, what the overall structure is or how you want to present it. But if you have deeply nested data, all you can do is dig into it. You might be able to write a recursive function, but it might also become very difficult to maintain if the data structure is complex.

Categories

Resources