Populate array in react-redux-firebase - react-redux-firebase

react-redux-firebase supports replacing ids with the corresponding value in a lookup object – like a join – through a config object called populates (and later using a convenient mapping function inside mapStateToProps).
Unfortunately, the documentation of react-redux-firebase is rather rudimentary in this area (and in others)...
Can someone tell me, whether it's possible to populate a list of ids?
For example:
// from:
{ friends: [1, 27, 42] }
// to:
{ friends: [
{ id: 1, name: 'Charlie' },
{ id: 27, name: 'Parker' },
{ id: 42, name: 'Brown' },
] }

Testing version 3.0.0, it seems that populating a list works exactly the same as replacing a single field. Instead of receiving back an object you will receive an array of replaced objects.

Related

MongoDB, change array of objects to an array of strings containing their ObjectId

I have an database full of objects that contain information, as well as other arrays of objects. I would like to change the inner arrays to only be arrays with each index as an ObjectId type with their respective ObjectId
I am using the mongoose populate function to retrieve this information later in the program. So only the ObjectId is needed for the reference.
job {
_id: 1,
name: "name",
parts: [
{ _id: ObjectId("5c790ce7d3dc8d00ccc2688c"), name: "name"},
{ _id: ObjectId("5c790ce7d3dc8d00ccc2688b"), name: "name"},
{ _id: ObjectId("5c790ce7d3dc8d00ccc2688a"), name: "name"},
]
}
Desired Result
job {
_id: 1,
name: "name",
parts: [
ObjectId("5c790ce7d3dc8d00ccc2688c"),
ObjectId("5c790ce7d3dc8d00ccc2688b"),
ObjectId("5c790ce7d3dc8d00ccc2688a")
]
}
I tried a few mongoDB queries from the command line but none of them are quite giving the result I need. This one has no errors, but it doesn't seem to change anything.
db.jobs.update(
{},
{
$set: {"parts.$[element]": "element._id"}
},
{
multi: true,
arrayFilters: [{ "element": {} }]
}
)
I'm not sure if this is possible or not using only the mongo shell.
Mongo v4.2 introduced pipelined updates this allows the use of aggregation operators within the update and more importantly updating a document using it's own values. which is what you want to achieve.
db.jobs.updateMany(
{},
[
{
'$set': {
'parts': {
'$map': {
'input': '$parts',
'as': 'part',
'in': '$$part._id'
}
}
}
}
]);
Unfortunately this is not possible for earlier Mongo versions. Specifically $arrayFilters allows you to filter an array but again prior to the new update syntax accessing own values within the update is not possible.
You'll have to iterate over all documents and do the update one by one in code.
As #Tom Slabbaert mentioned in the other answer you will have to use updates with aggregation pipelines available from v4.2 if you want to update the documents in bulk in one operation.
As an alternative to using $map, if you want only a single value at the top level and the value is accessible using the dot notation. You can simply use $set with the dot notation.
db.jobs.updateMany({}, [{
$set: { parts: "$parts._id" }
}])

EmberJS 2.7 How to restructure/reformat/customize data returned from the store

I have what I think is a very simple issue, but I just don't get how to do this data manipulation. This sadly didn't help, even though it's the same pain I am feeling with Ember.
Here is a route:
route/dashboard.js:
import Ember from 'ember';
export default Ember.Route.extend({
// this is for testing, normally we get the data from the store
model: function() {
return this.get('modelTestData');
},
modelTestData: [{
name: 'gear',
colorByPoint: true,
data: [
{y: 10, name: 'Test1'},
{y: 12, name: 'Test2'},
{y: 40, name: 'Test3'}
]
}],
});
The structure of the 'modelTestData' object has to be exactly like that as it is passed into a child component that needs it structured that way.
I can easily get my data from the API and put it into the model:
model: function() {
return this.store.get('category');
},
But then I need to restructure it...but how?
I have to somehow iterate over the categories collection and extract parts of data from each record to replace the 'data' part of the modelTestData object.
So I have 3 issues I am completely stumped on:
How to 'get at' the attributes I need from the model?
How to structure them as an array of objects with 'y' and 'name'?
How to assign that structure to the 'data' property of modelTestData instead of it being hardcoded?
Categories is a JSONAPI object like this:
{
"data":[
{
"id":"1",
"type":"categories",
"attributes":{
"name":"Carrying system",
"total-grams":"0.0"
}
},
{
"id":"2",
"type":"categories",
"attributes":{
"name":"Shelter system",
"total-grams":"0.0"
}
}
]
}
I need to map the grams value to 'y' and the name to 'name' in modelTestData.
Note that the category data is used in other routes for other purposes exactly as returned by the API. So I don't want to change the model structure itself, or what the API returns...that will break other parts of the app that do use 'category' in its original structure.
This is a specific use case that this route needs to massage the data to pass to the child component as per the structure of modelTestData.
I also wonder whether this data manipulation task belongs in a route?
Should I somehow do this in the serliazer adapter, creating a new structure as say 'categoryWeights' so I can then do:
model: function() {
return this.store.get('categoryWeights');
},
EDIT
I have managed to do this in the route, but it just gives me an array of objects. I need a single object containing 2 properties and an embedded array of objects.
model() {
return this.store.findAll('category')
.then(categories => categories.map(category => {
let data = {
y: category.get('totalGrams'),
name: category.get('name')
};
return data;
}))
},
This should probably go into a computed property:
dataForSubModel: Ember.computed('model.#each.totalGrams', 'model.#each.name', {
get() {
return [{name: 'gear', colorByPoint: true, this.get('model').map(m => ({y:m.get('totalGrams'), name:m.get('name')}))}
}
}),
The serializer is the wrong place, because its not that you need to convert it between the server and your app, but between your app and a strange component.
Actually the best thing would be to refactor the component.
Ok I got this to work in the route.
model() {
return this.store.findAll('category')
.then( function(categories) {
let data = [];
data = categories.map(category => {
return {
y: category.get('totalGrams'),
name: category.get('name')
}
});
return [{name: 'gear', colorByPoint: true, data}];
})
},
I still have the feeling this should be done in the adapter or serializer. Would be happy to see answers that show how to do that.

Can one add a complex type item to ListModel?

I would like to have a ListModel-like structure to display inputs of a simple state machine. Each input might consist of several strings/ints. So I need each item of the ListModel to be able to store a list of data (strings with names of the input's parameters, or dictionaries with strings etc). At the moment I cannot append an item with a list property to a ListModel.
So the ListModel looks like this:
ListView {
anchors.fill: parent
model: ListModel {
id: listModel
}
delegate: Text {
text: inputs[0]['name']
}
}
And when the state changes I want to update the model and append elements like this:
var state = {
name: "abcd",
inputs: [{name: 'a'}, {name: 'b'}, {name: 'c'}]
}
listModel.append(state);
Current version of the code returns error TypeError: Cannot read property 'name' of undefined. It does not see the list.
According to this question there might be issues with using lists in the items of ListModel. But it seems irrelevant to my case. Maybe I need to use lists and dicts differently in QML, maybe I had to write text: inputs[0].name in delegate (which I tried) or something else (suggestions?).
Could someone suggest how to make a more or less complex item (basically, it is standard JSON) in a ListModel? It is not clear, since documentation and blogs/questions deal with strings all the time. Is there some helpful documentation which I missed? What are good practices to do it in QML? Should I use some custom objects?
List data can be added to a ListElement, according to the documentation and as you correctly did in your imperative code. However, nested roles are not really arrays. They are ListModels themselves. That's because, by design, QML does not produce a notification if an element of an array changes, which would be a show-stopper in a model-view-delegate setting.
Since the nested role is a model, you can use model's functions. For instance, this example works fine:
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
id: window
width: 600
height: 400
visible: true
ListView {
anchors.fill: parent
model: ListModel {
id: listModel
}
delegate: Text {
text: name + inputs.get(index % inputs.count).name // accessing the inner model
}
}
MouseArea {
anchors.fill: parent
onClicked: {
var state = {
name: "abcd",
inputs: [{name: 'a'}, {name: 'b'}, {name: 'c'}]
}
listModel.append(state);
}
}
}
According to your question, the input is plain JSON. In that case, consider the usage of JSONListModel in place of ListModel. It exposes a set of API which matches XMLListModel, via JSONPath, and could possibly represent the perfect solution for your scenario.

Push new items into JSON array

Let's say this is the table inside my collection:
{
"_id" : ObjectId("557cf6bbd8efe38c627bffdf"),
"name" : "John Doe",
"rating" : 9,
"newF" : [
"milk",
"Eggs",
"Beans",
"Cream"
]
}
Once a user types in some input, it is sent to my node server, and my node server then adds that item to the list "newF", which is then sent back to my MongoDB and saved.
I'm trying to use update, which can successfully change the values inside of this table, but I'm not sure how to add new items onto that list. I did it with $push inside the MongoDB shell, but not sure how to do it on node.
Here's a snippet of my code:
db.collection('connlist').update({ _id: new ObjectId("e57cf6bb28efe38c6a7bf6df")}, { name: "JohnDoe", rating: 9, newF: ["Milk, Eggs", "Beans"] }, function(err,doc){
console.log(doc);
});
Well the syntax for adding new items is just the same as in the shell:
// make sure you actually imported "ObjectID"
var ObjectId = require('mongodb').ObjectID;
db.collection('conlist').update(
{ "_id": new ObjectId("e57cf6bb28efe38c6a7bf6df") },
{ "$push": { "newF": { "$each": [ "cream", "butter" ] } } },
function(err,numAffected) {
// do something in the callback
}
)
Or perhaps use .findOneAndUpdate() if you want to return the modified document instead of just making the alteration.
Of course use $push and possibly with $each which allows multiple array elements to be added when adding to an array. If you want "unique" items then use $addToSet where your operation allows.
And generally speaking for other items you should use $set or other operators in the update portion of your document. Without these operators you are just "replacing" the document content with whatever structure you place in the "update" portion of your statement.

How to return a Date value from JSON to Google Visualization API

is there a way to retrieve date value from JSON in Google Visualization API?
Here is the snipplet for playground please copy the code below into it
When you run the code you won't have anything in result. you should remove the quotes from the date value I marked with comment in order to retrieve result.
function drawVisualization() {
var JSONObject = {
cols:
[
{id: 'header1', label: 'Header1', type: 'string'},
{id: 'header2', label: 'Header2', type: 'date'}
],
rows:
[
{
c:
[
{v: 'Value1'},
{v: "new Date(2010, 3, 28)"} // <= This is the format I receive from WebService
]
},
{
c:
[
{v: 'Value2'},
{v: new Date(2010, 3, 28)} // <=This is the format Google API accepts
]
}
]
};
var data = new google.visualization.DataTable(JSONObject, 0.5);
visualization = new google.visualization.Table(document.getElementById('table'));
visualization.draw(data, {'allowHtml': true});
}
I just ran into this problem myself, so I thought I'd paste the answer from the google api documentation, located here http://code.google.com/apis/chart/interactive/docs/dev/implementing_data_source.html#jsondatatable
"JSON does not support JavaScript Date values (for example, "new Date(2008,1,28,0,31,26)"; the API implementation does. However, the API does now support a custom valid JSON representation of dates as a string in the following format: Date(year, month, day[,hour, minute, second[, millisecond]]) where everything after day is optional, and months are zero-based."
I was running into same problem and above solution did not work. After searching for hours I found following post and the solution in there worked.
https://groups.google.com/forum/#!msg/google-visualization-api/SCDuNjuo7xo/ofAOTVbZg7YJ
Do not include "new" in the json string so it will be just:
v:"Date(2009, 9, 28)"
I suppose that the quote is not at the correct place in your snippet "new Date(2010, 3, 28")
Write instead "new Date(2010, 3, 28)"
Json format does not accept javascript object so the server return a string.
JSON knows only numbers, boolean constants, string, null, vector and 'object' (much more a dictionnary).
I suppose that you have to perform an eval() of the returned string (do not forget to check inputs).
Another alternative is to use a Regex to extract the fields something like /new Date\((\d+),(\d+),(\d+)\)/ will work.