The chart trying to create as shown below
the working fiddle is as shown below
https://jsfiddle.net/BlackLabel/xy6ftpn5/
how to stack the multiple markers on the same date as in the picture. Tried to add multiple series
in series parameter
also need trying to figure out how to show multiple y-axis separately for different chart like line marker and bar chart
any pointers will help
You just need to define the yAxis property as an array with multiple objects and then assign each series to the proper yAxis. For example:
yAxis: [{
...
}, {
...
}, {
...
}],
series: [{
...,
yAxis: 0
}, {
...,
yAxis: 1
}, {
...,
yAxis: 1
}, {
...,
yAxis: 2
}]
Live demo: https://jsfiddle.net/BlackLabel/oqbzcm7y/
API Reference: https://api.highcharts.com/highcharts/series.line.yAxis
Docs: https://www.highcharts.com/docs/chart-concepts/axes
Related
I am using $geoNear to search for a business location based of a users location. However when I perform the search, Mongo only allows me to index 1 geo-location some businesses have multiple location, and I would like to be able to turn the location index to find the closest result.
This is what I currently have:
location : {
type: { type: String, default: "Point" },
coordinates: { type: [Number], default: [115.8575,-31.953] },
},
And this is what I would like to have:
location : [{
name: "Suburb 1",
type: { type: String, default: "Point" },
coordinates: { type: [Number], default: [115.8575,-31.953] },
},
{
name: "Suburb 2",
type: { type: String, default: "Point" },
coordinates: { type: [Number], default: [115.8575,-31.953] },
}],
Where the search would find the closest result. Is there an ideal way to do this?
Thanks
If you would like to use $geoNear, you should consider redesigning your data model. $geoNear would return you the closest location (sorted), and it requires geospatial-index(es).
A suggestion would be to store a single document entry per business location.
You may also find Tutorial: Geospatial useful especially the examples.
Consider the following posts collection:
{
_id: 1,
title: "Title1",
category: "Category1",
comments: [
{
title: "CommentTitle1",
likes: 3
},
{
title: "CommentTitle2",
likes: 4
}
]
}
{
_id: 2,
title: "Title2",
category: "Category2",
comments: [
{
title: "CommentTitle3",
likes: 1
},
{
title: "CommentTitle4",
likes: 4
}
]
}
{
_id: 3,
title: "Title3",
category: "Category2",
comments: [
{
title: "CommentTitle5",
likes: 1
},
{
title: "CommentTitle6",
likes: 3
}
]
}
I want to retrieve all the posts, and if one post has a comment with 4 likes I want to retrieve this comment only under the "comments" array. If I do this:
db.posts.find({}, {comments: { $elemMatch: {likes: 4}}})
...I get this (which is exactly what I want):
{
_id: 1,
comments: [
{
title: "CommentTitle2",
likes: 4
}
]
}
{
_id: 2,
comments: [
{
title: "CommentTitle4",
likes: 4
}
]
}
{
_id: 3
}
But how can I retrieve the remaining fields of the documents without having to declare each of them like below? This way if added more fields to the post document, I wouldn't have to change the find query
db.posts.find({}, {title: 1, category: 1, comments: { $elemMatch: {likes: 4}}})
Thanks
--EDIT--
Sorry for the misread of your question. I think you'll find my response to this question here to be what you are looking for. As people have commented, you cannot project this way in a find, but you can use aggregation to do so:
https://stackoverflow.com/a/21687032/2313887
The rest of the answer stands as useful. So I think I'll leave it here
You must specify all of the fields you want or nothing at all when using projection.
You are asking here essentially that once you choose to alter the output of the document and limit how one field is displayed then can I avoid specifying the behavior. The bottom line is thinking of the projection part of a query argument to find just like SQL SELECT.It behaves in that * or all is the default and after that is a list of fields and maybe some manipulation of the fields format. The only difference is for _id which is always there by default unless specified otherwise by excluding it, i.e { _id: 0 }
Alternately if you want to filter the collection you nee to place your $elemMatch in thequery itself. The usage here in projection is to explicitly limit the returned document to only contain the matching elements in the array.
Alter your query:
db.posts.find(
{ comments: { $elemMatch: {likes: 4}}},
{ title: 1, category: 1, "comments.likes.$": 1 }
)
And to get what you want we use the positional $ operator in the projection portion of the find.
See the documentation for the difference between the two usages:
http://docs.mongodb.org/manual/reference/operator/query/elemMatch/
http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/
This question is pretty old, but I just faced the same issue and I didn't want to use the aggregation pipeline as it was simple query and I only needed to get all fields applying an $elemMatch to one field.
I'm using Mongoose (which was not the original question but it's very frequent these days), and to get exactly what the question said (How can I retrieve all the fields when using $elemMatch?) I made this:
const projection = {};
Object.keys(Model.schema.paths).forEach(key => {
projection[key] = 1;
});
projection.subfield = { $elemMatch: { _id: subfieldId } };
Model.find({}, projection).then((result) => console.log({ result });
This question almost boils down to this "faceted search, multiple multivalued fields, sorted by weight rather than count".
The database
I have about 10M events, each with multiple editions, each edition being described by tags. There are 5 tag types (places, speakers, participants, topics, industries).
{
title: "CES",
editions: [
{
date: "2013-02-01",
tags: [ {label: "Eric Schmidt", type: "speaker", "popularity": 50}, {label: "Paris", type: "place", "popularity": 30} ]
},
{
date: "2012-01-23",
tags: [ ... ]
}
]
}
Data logic
Tags are hierarchical, for example, "Eric Schmidt" is filed under Google who is filed under Tech companies. So, whenever Eric is at an event, all three tags are associated with the event.
Different tags can have different popularity, meaning "Eric Schmidt" would have a popularity of 100, but "Eileen Naughton" would have a popularity of "10".
The popularity does not apply hierarchically. That means that, if "Eric Schmidt" would leave Google for Foursquare, his popularity would still be 100 and Foursquare would still have popularity 50.
If at a given time, we find out another "participant" attended, for example, we need to be able to add him as a tag
Search requirements
Now, imagine a left-hand menu with 4 sections:
Places
------------
Paris
London
New York
[more]
Speakers
----------
Google
Facebook
Marc Zuckerberg
[more]
and so on.
Whenever the user clicks on a tag, I want the menu to reflect the results and allow him to drill down further (faceted search). The twist is that when deciding to show "Google" vs "Eric Schmidt" vs "Foursquare" in the first three tags in each section, I want to make sure the most popular tag is shown higher, based on the [number of matching events] * [tag popularity]. That means that if there are 3 matching events for "Foursquare" and only one for "Eric Schmidt" it should show Foursquare first, with a score of 3*50 = 150 vs Schmidt's 1 * 100.
Also, ideally, if I select "Google" then, for the "speakers" section, the system should not return speakers outside Google, even if the matching events also have "Zuckerberg" listed, with a huge popularity of 200. So, the returned tags should reside "beneath" the current selection in each section, and their sorting should be based on the above scoring logic.
Current MongoDB solution
Store a separate document for each edition:
{
event: "CES",
date: "2013-02-01",
tags: [ {label: "Eric Schmidt", type: "speaker", "popularity": 50, path: ",Tech Companies,Google,"}, {label: "Paris", type: "place", "popularity": 30, path: ",Europe,France,"} ]
},
{
event: "CES",
date: "2012-01-23",
tags: [ ... ]
}
Use the aggregation framework
*One query for each tag type (5 queries per request) *
db.events.aggregate(
{
'$match': {'tags.label': {'$all': ["selected tag 1", "selected tag2", ...]}}
},
{
'$unwind': '$tags'
},
// group by events, so we can later sum each tag's popularity only once per event, not per event edition
{
'$group': {
'_id': '$event',
'taglistUnqiue': {
'$addToSet': {
'label': '$tags.label',
'type': '$tags.type',
'popularity': '$tags.popularity'
}
}
}
},
{
'$unwind': '$taglist'
},
{
'$match': {
'taglist.type': "speaker",
/* haven't tested this path-matching, but it should work
to only get the tags that are in the bottom tree
of the current selected speaker tag */
'taglist.path': /^,selected speaker tag,/,
}
},
{
'$group': {
'_id': '$taglist.label',
'score': {
'$sum': '$taglist.popularity'
}
}
});
Ok, this should work, algorithmically, but performance wise it will surely not work for 50M event editions, each with thousands of possible tags.
Can anyone think of another approach? Can this approach be optimized in any way other than using "Map/Reduce" which I understand is way too slow to perform on-the-fly for each user?
depending on how "live" your search needs to be, have you considered using incremental map/reduce?
http://docs.mongodb.org/manual/tutorial/perform-incremental-map-reduce/
I have this data :
{ "identifier": "id", "idAttribute":"id", "label": "date",
"items": [
{ "id":1,
"name":"index",
"point":[{"id":1,"num":17, "date":"2009-02-01"},
{"id":2,"num":10, "date":"2009-06-01"}
]},
{ "id":2,
"name":"high",
"point":[{"id":1,"num":11, "date":"2009-01-01"},
{"id":2,"num":19, "date":"2009-09-01"}
]},
{ "id":3,
"name":"low",
"point":[{"id":1,"num":14, "date":"2009-07-01"},
{"id":2,"num":20, "date":"2009-03-01"}
]}
]}
I want to display it in this chart.
Also, I don’t know how can I put the month’s date in the labels.
dojo.require(”dojox.charting.DataChart”);
dojo.require(”dojo.data.ItemFileWriteStore”);
dojo.addOnLoad(function() {
dojo.require("dojox.charting.DataChart");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.addOnLoad(function() {
var store = new dojo.data.ItemFileWriteStore({
url: "exemple_stock.json"
});
chart = new dojox.charting.DataChart("chartDiv" ,{ displayRange:12,
xaxis:{labels:["0", "Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"]},
yaxis:{max:100,min:0, majorTickStep:10, maxLabelSize:30},
type: dojox.charting.plot2d.Lines
});
chart.setStore(store, {symbol:"*"}, "point"); // <-- single value property
});
I don't know how to do it with DataChart, but regular Dojo charts can do any kind of labels without problems: http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_labels2d.html
If you need to use a dojo.data store as your data source, consider using DataSeries with regular charts:
http://docs.dojocampus.org/dojox/charting#using-dojo-data-data-sources-with-charts
http://dojotoolkit.org/api/dojox/charting/DataSeries.html
http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_DataSeries.html
I'm developing a webapp which has a portal-ish component to it (think like multiple panels that can be drug around from column to column and added or removed). I'm using MongoDB to store this info with a format like so...
{
_id: ObjectId(...),
title: 'My Layout',
columns: [
{
order: 1,
width: 30,
panels: [
{ title: 'Panel Title', top: 100, content: '...' },
{ title: 'Panel Title', top: 250, content: '...' },
]
},
{
... multiple columns ...
}
]
}
I'm attempting to use atomic/modifier operations with update() and this is getting confusing. If I wanted to just update one property of a specific panel, how do I reference that?
update(
{ _id: ObjectId(...) },
{ $set: { columns.[???].panels.[???].top: 500 }
)
If you know the index in the array you can access the array element directly using dot notation.
update(
{ _id: ObjectId(xxxx) },
{ $set: { 'columns.0.panels.0.top' : 125}}
)
Make sure you encase the dot notated path in quotes as a string.
Edit:
To give more detail on how this could work dynamically, I'll give an example in PHP:
$action = array("columns.$colNum.panels.$panelNum" => $newValue);
Yes there is the positional operator, but it does not appear to be advanced enough to change arrays within arrays, this may change in MongoDB 1.7.0
There is an alternative you can do instead of trying to stuff this information into a nested document. Try to flatten it out. You can create a collection that has panel & column objects:
column object:
{
_id: // MongoId
type: 'column',
user: 'username',
order: 1,
width: 30,
}
panel object:
{
_id: //MongoId
type: 'panel',
user: 'username',
parentColumn: //the columns _id string
top: 125,
left: 100
}
Then you can find all columns that belong to a user by doing:
find({ type: 'column', user:'username'});
You can find all panels for a specific column by doing:
find({type: 'panel', columnOwner:'ownerID'});
Since each column and panel will have a unique ID given by MongoDB to it, you can easily query and atomically set options.
update({'_id': ObjectId('idstring')}, {$set : { 'top' : 125}});
I too had a situation like this, i followed $addToSet after $pull to replace i.e update what i needed.
update(
{ _id: ObjectId(...) },
{ $addToSet: { columns.$.panels : "new sub-Doc" }
)
And then remove the old value
update({_id:ObjectId(....)},{$pull : { columns.$.panels : {"top" : 100} }})