I'm trying to get the value from a collection which looks a little confusing for me.
Collection looks like this
{
"_id" : "bqaGRGotKzYiA6mZv",
"0" : {
"MessageId" : "8B25CEB0-9EC6-48F7-9826-0AC813E903F8",
"Requested" : ISODate("2015-10-08T16:47:40.173Z")
},
"1" : {
"MessageId" : "B02935F0-8492-4858-B8C1-0BCEA9BCC80B",
"Requested" : ISODate("2015-10-08T16:59:45.503Z")
},
"2" : {
"MessageId" : "F766B029-BB81-4E6C-90B5-71B51B8F77FA",
"Requested" : ISODate("2015-10-08T16:47:22.956Z")
},
"3" : {
"MessageId" : "D88D87EE-CD25-4624-8265-8D66D8D9163A",
"Requested" : ISODate("2015-10-08T17:24:20.906Z")
}
}
Now I want to display to client a table with "Requested" values in 1 column
is there any other way than pointing each number manually?
This is the helper
myHelper: function(){
return Tasks.find();
}
and the code below will print the "ISODate("2015-10-08T16:47:40.173Z")"
{{#each myHelper}}
{{[0].Requested}}
{{/each}}
But I want some automatic action because I don't know how many numbers will be in collection.
I may not tell what you expect or need to accomplish your goal, but the collection organization approach you have taken feels a bit odd to me. So I'll post my answer, too.
If you had a collection item like this
{
"_id": "bqaGRGotKzYiA6mZv",
"messages": [{
"MessageId": "8B25CEB0-9EC6-48F7-9826-0AC813E903F8",
"Requested": ISODate("2015-10-08T16:47:40.173Z")
}, {
"MessageId": "B02935F0-8492-4858-B8C1-0BCEA9BCC80B",
"Requested": ISODate("2015-10-08T16:59:45.503Z")
}, {
"MessageId": "F766B029-BB81-4E6C-90B5-71B51B8F77FA",
"Requested": ISODate("2015-10-08T16:47:22.956Z")
}, {
"MessageId": "D88D87EE-CD25-4624-8265-8D66D8D9163A",
"Requested": ISODate("2015-10-08T17:24:20.906Z")
}]
}
or, even if you need to store items' IDs explicitly, like this:
{
"_id": "bqaGRGotKzYiA6mZv",
"messages": [{
"id": 0,
"MessageId": "8B25CEB0-9EC6-48F7-9826-0AC813E903F8",
"Requested": ISODate("2015-10-08T16:47:40.173Z")
}, {
"id": 1,
"MessageId": "B02935F0-8492-4858-B8C1-0BCEA9BCC80B",
"Requested": ISODate("2015-10-08T16:59:45.503Z")
}, {
"id": 2,
"MessageId": "F766B029-BB81-4E6C-90B5-71B51B8F77FA",
"Requested": ISODate("2015-10-08T16:47:22.956Z")
}, {
"id": 3,
"MessageId": "D88D87EE-CD25-4624-8265-8D66D8D9163A",
"Requested": ISODate("2015-10-08T17:24:20.906Z")
}]
}
then you would be able to provide the data from helper to the template like this:
myHelper: function(_id) {
return Tasks.find({
_id: _id
});
}
and use it like this:
{{#each myHelper}}
{{#each message}}
{{MessageId}}
{{Requested}}
{{/each}}
{{/each}}
You could also add messages items to a collection item like this:
var theMessage = {
"MessageId": "whatever",
"Requested": "whenever"
}
Tasks.update({
_id: _id
}, {
$push: {
messages: theMessage
}
});
Create global helper that will convert each object from your collection to an array.
Template.registerHelper("convertToArray", function(){
var self = this; //this points to single object from collection.
var array = [];
var keys = _.without(Object.keys(this), "_id");
keys.forEach(function(key){
array.push(self[key]);
})
return array;
});
Optionally you can sort keys before looping through it.
Then use it like this:
{{#each myHelper}}
{{#each convertToArray}}
{{Requested}}
{{/each}}
{{/each}}
Related
I'm new to Mongoose and I've been trying for days on how to solve this issue and I'm still having trouble.
My document object is below.
"person" : [
{
"title" : "front-end developer",
"skills" : [
{
"name" : "js",
"project" : "1",
},
{
"name" : "CSS",
"project" : "5",
}
]
},
{
"title" : "software engineer",
"skills" : [
{
"name" : "Java",
"project" : "1",
},
{
"name" : "c++",
"project" : "5",
}
]
}
]
What I would like accomplish is to return all documents that have person.title = software engineer AND person.skills.name = c++. The skill c++ has to belong to the software engineer person object. So returning documents when a front-end developer has c++ is not ideal.
Here's what I've tried doing so far. The query works but it returns documents which meet either one of the conditions and not both.
var query = {
_id: { $nin: [userID] },
$and: [
{person: {
$elemMatch: {
name: {$regex: `^${titleName}$`, $options: "i"}
}
}},
{[`person.skills`]: {
$elemMatch: {
name: {$regex: `^${skillName}$`, $options: "i"}
}
}}
]
};
Any help would be greatly appreciated. Thanks!
You can try below query. Move the and condition inside the $elemMatch
var query = {
"_id": {
"$nin": [userID]
},
"person": {
"$elemMatch": {
"name":{$regex: `^${titleName}$`, $options: "i"},
"skills.name": {$regex: `^${skillName}$`, $options: "i"}
}
}
};
Using: MongoDB and native nodeJS mongoDB driver.
I'm trying to parse all the data from fb graph api, send it to my API and then save it to my DB.
PUT handling in my server:
//Update user's data
app.put('/api/users/:fbuser_id/:category', function(req, res) {
var body = JSON.stringify(req.body);
var rep = /"data":/;
body = body.replace(rep, '"' + req.params.category + '"' + ':');
req.body = JSON.parse(body);
db.fbusers.update({
id: req.params.fbuser_id
}, {
$set: req.body
}, {
safe: true,
multi: false
},
function(e, result) {
if (e) return next(e)
res.send((result === 1) ? {
msg: 'success'
} : {
msg: 'error'
})
});
});
I'm sending 25 elements at a time, and this code just overrides instead of updating the document.
Data I'm sending to the API:
{
"data": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Basically my API changes "data" key from sent json to the category name, f.e.:
PUT to /api/users/000/likes will change the "data" key to "likes":
{
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Then this JSON is put to the db.
Hierarchy in mongodb:
{
"_id": ObjectID("556584c8e908f0042836edce"),
"id": "0000000000000",
"email": "XXXX#gmail.com",
"first_name": "XXXXXXXX",
"gender": "male",
"last_name": "XXXXXXXXXX",
"link": "https://www.facebook.com/app_scoped_user_id/0000000000000/",
"locale": "en_US",
"name": "XXXXXXXXXX XXXXXXXXXX",
"timezone": 3,
"updated_time": "2015-05-26T18:11:59+0000",
"verified": true,
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
....and so on
}
]
}
So the problem is that my api overrides the field (in this case "likes") with newly sent data, instead of appending it to already existing data document.
I am pretty sure that I should be using other parameter than "$put" in the update, however, I have no idea which one and how to pass parameters to it programatically.
Use $push with the $each modifier to append multiple values to the array field.
var newLikes = [
{/* new item here */},
{/* new item here */},
{/* new item here */},
];
db.fbusers.update(
{ _id: req.params.fbuser_id },
{ $push: { likes: { $each: newLikes } } }
);
See also the $addToSet operator, it adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array.
Scenario: Consider the document present in the MongoDB in collection named twitCount.
{
"_id" : ObjectId("53d1340478441a1c0d25c40c"),
"items" : [
{
"date" : ISODate("2014-07-22T22:18:05.000Z"),
"value" : 4,
"_id" : ObjectId("53d134048b3956000063aa72")
},
{
"date" : ISODate("2014-07-21T22:09:20.000Z"),
"value" : 10,
"_id" : ObjectId("53d134048b3956000063aa71")
}
...
],
"ticker" : "OM:A1M"
}
I only want to fetch the first and last date inside "items". I've tried lot of different "queries". But I cannot get it right. The "ticker" is unique
The following query is the only one that returns something, but it returns everything(that is expected).
twitCount.aggregate([{ $match : { ticker: theTicker}} ], function(err, result){
if (err) {
console.log(err);
return;
}
console.log(result)
})
So, In the end I want the query to return it something like this [2013-02-01, 2014-07-24];
I really need help with this, all links on manual/core/aggregation are purple and I don't know where to get more information.
Hard to tell if your intent here is to work with a single document or multiple documents that match your condition. As suggested, a single document would really just involve using the shift and pop methods native to JavaScript on the singular result to get the first and last elements of the array. You might also need to employ array sort here
twitCount.findOne({ "ticker": "OM:A1M" },function(err,doc) {
doc.items = doc.items.sort(function(a,b) {
return ( a.date.valueOf() > b.date.valueOf() ) ? 1
: ( a.date.valueOf() < b.date.valueOf() ) ? -1 : 0;
});
doc.items = [doc.items.shift(),doc.items.pop()];
console.log( doc );
})
The other suggestions don't really apply as operators like $pop permanently mondify the array in updates. And the $slice operator that can be used in a query would really only be of use to you if the array contents are already sorted, and additionally you would be making two queries to return first and last, which is not what you want.
But if you really are looking to do this over multiple documents then the aggregation framework is the answer. The key area to understand when working with arrays is that you must use an $unwind pipeline stage on the array first. This "de-normalizes" to a form where a copy of the document is effectively produced for each array element:
twitCount.aggregate([
// Match your "documents" first
{ "$match": { "ticker": "OM:A1M" } },
// Unwind the array
{ "$unwind": "$items" },
// Sort the values
{ "$sort": { "items.date": 1 } },
// Group with $first and $last items
{ "$group": {
"_id": "$ticker",
"first": { "$first": "$items" },
"last": { "$last": "$items" }
}}
],function(err,result) {
If you really want "items" back as an array then you can just do things a little differently:
twitCount.aggregate([
// Match your "documents" first
{ "$match": { "ticker": "OM:A1M" } },
// Unwind the array
{ "$unwind": "$items" },
// Sort the values
{ "$sort": { "items.date": 1 } },
// Group with $first and $last items
{ "$group": {
"_id": "$ticker",
"first": { "$first": "$items" },
"last": { "$last": "$items" },
"type": { "$first": { "$const": [true,false] } }
}},
// Unwind the "type"
{ "$unwind": "$type" },
// Conditionally push to the array
{ "$group": {
"_id": "$_id",
"items": {
"$push": {
"$cond": [
"$type",
"$first",
"$last"
]
}
}
}}
],function(err,result) {
Or if your $match statement is just intended to select and you want the "first" and "last" from each document "_id" then you just change the key in the initial $group to "$_id" rather than the "$ticker" field value:
twitCount.aggregate([
// Match your "documents" first
{ "$match": { "ticker": "OM:A1M" } },
// Unwind the array
{ "$unwind": "$items" },
// Sort the values
{ "$sort": { "items.date": 1 } },
// Group with $first and $last items
{ "$group": {
"_id": "$_id",
"ticker": { "$first": "$ticker" },
"first": { "$first": "$items" },
"last": { "$last": "$items" },
"type": { "$first": { "$const": [true,false] } }
}},
// Unwind the "type"
{ "$unwind": "$type" },
// Conditionally push to the array
{ "$group": {
"_id": "$_id",
"ticker": { "$first": "$ticker" },
"items": {
"$push": {
"$cond": [
"$type",
"$first",
"$last"
]
}
}
}}
],function(err,result) {
In that last case, you would get something like this, based on the data you have provided:
{
"_id" : ObjectId("53d1340478441a1c0d25c40c"),
"ticker" : "OM:A1M",
"items" : [
{
"date" : ISODate("2014-07-21T22:09:20Z"),
"value" : 10,
"_id" : ObjectId("53d134048b3956000063aa71")
},
{
"date" : ISODate("2014-07-22T22:18:05Z"),
"value" : 4,
"_id" : ObjectId("53d134048b3956000063aa72")
}
]
}
You can find the Full List of Aggregation Operators in the documentation. It is worth getting to know how these function as depending on what you are doing the aggregation framework can be a very useful tool.
I am using loopjs tokeninput in a View. In this scenario I need to prePopulate the control with AdminNames for a given Distributor.
Code Follows :
$.getJSON("#Url.Action("SearchCMSAdmins")", function (data) {
var json=eval("("+data+")"); //doesnt work
var json = {
"users": [
eval("("+data+")") //need help in this part
]
}
});
$("#DistributorCMSAdmin").tokenInput("#Url.Action("SearchWithName")", {
theme: "facebook",
preventDuplicates: true,
prePopulate: json.users
});
There is successful return of json values to the below function. I need the json in the below format:
var json = {
"users":
[
{ "id": "1", "name": "USER1" },
{ "id": "2", "name": "USER2" },
{ "id": "3", "name": "USER3" }
]
}
I am having a JSON data like below.
{
"divisions": [{
"name": "division1",
"id": "div1",
"subdivisions": [{
"name": "Sub1Div1",
"id": "div1sub1",
"schemes": [{
"name": "Scheme1",
"id": "scheme1"
}, {
"name": "Scheme2",
"id": "scheme2"
}]
}, {
"name": "Sub2Div1",
"id": "div1sub2",
"schemes": [{
"name": "Scheme3",
"id": "scheme3"
}]
}
]
}]
}
I want to read this into a TreeStore, but cannot change the subfields ( divisions, subdivisions, schemes ) to be the same (eg, children).
How can achieve I this?
When nested JSON is loaded into a TreeStore, essentially the children nodes are loaded through a recursive calls between TreeStore.fillNode() method and NodeInterface.appendChild().
The actual retrieval of each node's children field is done within TreeStore.onNodeAdded() on this line:
dataRoot = reader.getRoot(data);
The getRoot() of the reader is dynamically created in the reader's buildExtractors() method, which is what you'll need to override in order to deal with varying children fields within nested JSON. Here is how it's done:
Ext.define('MyVariJsonReader', {
extend: 'Ext.data.reader.Json',
alias : 'reader.varijson',
buildExtractors : function()
{
var me = this;
me.callParent(arguments);
me.getRoot = function ( aObj ) {
// Special cases
switch( aObj.name )
{
case 'Bill': return aObj[ 'children' ];
case 'Norman': return aObj[ 'sons' ];
}
// Default root is `people`
return aObj[ 'people' ];
};
}
});
This will be able to interpret such JSON:
{
"people":[
{
"name":"Bill",
"expanded":true,
"children":[
{
"name":"Kate",
"leaf":true
},
{
"name":"John",
"leaf":true
}
]
},
{
"name":"Norman",
"expanded":true,
"sons":[
{
"name":"Mike",
"leaf":true
},
{
"name":"Harry",
"leaf":true
}
]
}
]
}
See this JsFiddle for fully working code.