I have an array that looks like this:
[{
LocalBond:"0",
LocalCash:"2.42",
LocalEquity:"0",
ForeignEquity: "4",
...
}]
What I want it look like:
[{
Source: "LocalBond",
Value: "0"
},
Source: "LocalCash",
Value: "2.42"
},
Source: "LocalEquity",
Value: "0"
},
{...}
]
I want to turn a single object into many objects. I also need the exclude the 'ForeignEquity' result.
I tried using _.map, and returning the fields I want, but I am struggling a bit. Am I on the right track? When I pass more than one parameter into my function, I don't get the desired result.
The most simple code is pure javascript:
Using for..in access to the property of the object, and inside of the for loop build the array.
http://www.w3schools.com/jsref/jsref_forin.asp
Example:
https://jsfiddle.net/jewrsL8a/5/
var collection = [{
LocalBond:"0",
LocalCash:"2.42",
LocalEquity:"0",
ForeignEquity: "4"
}];
var result = [];
for (var property in collection[0]) {
if(property!=='ForeignEquity'){
result.push({'Source': property, 'Value': collection[0][property]});
}
}
console.log(result);
Related
I have a project where we have been using simple, unversioned values for documents:
{
_id: <someid>,
prop1: 'foo',
prop2: 'bar',
prop3: 'baz'
}
I would like to update the method that saves prop values to start saving values as versions in an array, to look like this:
{
_id: <someid>,
prop1: [{ value: 'foo', createdAt: <someDate>}],
prop2: [{ value: 'bar', createdAt: <someDate>}, { value: 'barrrrr', createdAt: <someDate>}],
prop3: 'baz'
}
I would like, in my update query, to $push the new prop value object if it's already an array, or to $set it to `[{ value: 'newvalue', createdAt: +new Date()}] if not. Ideally, this would let me seamlessly transition the data to be versioned over time. On the retrieval side, if it's not an array we just treat the only value that's there as the reference version, and whenever anything gets updated, that prop is converted to the new format.
I've been struggling to find an example of that same use case: can anyone point me in the right direction?
UPDATE:
After being pointed in the right direction, I was able to use the aggregation pipeline in combination with update to do what I wanted. Part of the key was to abandon trying to pivot between setting and pulling--instead, I could use the helper method $concatArrays to accomplish the array addition a different way. Here's the basic shell code I got to work, purely to show the structure:
db.test.docs.update({ key: 2 }, [
{
$set: {
prop2: {
$cond: {
if: { $isArray: '$prop2' },
then: {
$concatArrays: [
'$prop2',
[
{
value: 'CONCAT!'
}
]
]
},
else: [
{
value: 'SET!'
}
]
}
}
}
}
]);
In MongoDB 4.2 you can use the pipeline form of update to use aggregation stages and operators to do that.
You would likely need to use $cond and $type to find out if the field already contains an array, and then $concatArrays to combine the values.
I am trying to access a nested object in ReactJS. This is what the object looks like:
const characteristics = [
{ id: "geo", content: 'Geopolitical' },
{ id: "dog", content: 'Dog Loving' },
];
const starterColumns = {
"1": {
name: 'I am',
items: characteristics
},
"2": {
name: 'fullstack developer',
items: []
}
}
const [columns, setColumns] = useState(starterColumns);
This is the error I get when I try to console.log(columns['2']['items']['0']['id']):
TypeError: Cannot read property 'id' of undefined
Does this have to do with the fact that I am working with a stateful variable? Is something funky going on with the nested objects? Thanks for the help!
EDIT
The problem was that there was no object in the column so I had no object to access. Now the problem outstanding is how do I fill that void without displaying a new drag and drop piece. Thanks for helping!
EDIT
I used a try/catch statement to check the object so if it is empty, nothing happens.
Use try catch only for errors that you can't handle
To access an element use dot notation whenever it's possible instead of using bracket notation []
When there is an empty array in the items you can't access to the id you will get an error so the solution is to check if the array is not empty
columns['2'].items.length > 0
To access the first element of an array you have to use [0] instead of ['0']
try this solution
if (columns['2'].items.length > 0) {
console.log(columns['2'].items[0].id)
}
I'm trying to represent a JSON structure in swift for use with EVReflection. The string looks like this:
{
"date": 2457389.3333330001,
"results":
{
"sun": [[559285.95145709824, 202871.33591198301, 61656.198554897906], [127.6163120820332, 948.44727756795123, 406.68471093096883]],
... etc ...
"geomoon": [[-401458.60657087743, -43744.769596474769, -11058.709613333322], [8433.3114508170656, -78837.790870237863, -26279.67592282737]]
},
"unit": "km"
}
I've tried several approaches to model the inner "results" dictionary, which is keyed with a string and always has values that are an array of two elements, each of which have three doubles (i.e., [String: [[Double]]] is one model I've tried). No matter what I do, I get an error along these lines:
ERROR: valueForAny unkown type , type _NativeDictionaryStorage<String, Array<Array<Double>>>. Could not happen unless there will be a new type in Swift.
Does anyone have an idea how to model this so EVReflection is happy? I've also had the sense from the phrase Could not happen unless there will be a new type in Swift that there's another method or different modeling with explicit subtypes I can add that would give it what it needs, but I can't puzzle out what to do from the docs.
In Swift a Double is a struct. Doing reflections with structs have some limitations. I prefer using NSNumber instead.
My first thought would be an object model like this:
class MyObject: EVObject {
var date: NSNumber?
var results: Result?
var unit: String?
}
class Result: EVObject {
var sun: [[NSNumber]]?
var geomoon: [[NSNumber]]?
}
But your object has a nested value. Until now I never have tested EVReflection with a structure like this. I will try adding a unit test for this in a moment. It would have been easier if the inner array was an object (something like an object with an x, y and z value?)
Update:
This seems to work. I tested this with the following unitTest:
func testNestedArry() {
let json = "{\"date\": 2457389.3333330001,\"results\": { \"sun\": [[559285.95145709824, 202871.33591198301, 61656.198554897906], [127.6163120820332, 948.44727756795123, 406.68471093096883]], \"geomoon\": [[-401458.60657087743, -43744.769596474769, -11058.709613333322], [8433.3114508170656, -78837.790870237863, -26279.67592282737]] }, \"unit\": \"km\" }"
let myObject = MyObject(json: json)
print(myObject.toJsonString())
}
And the output of myObject was:
{
"date" : 2457389.333333,
"results" : {
"sun" : [
[
559285.9514570982,
202871.335911983,
61656.19855489791
],
[
127.6163120820332,
948.4472775679512,
406.6847109309688
]
],
"geomoon" : [
[
-401458.6065708774,
-43744.76959647477,
-11058.70961333332
],
[
8433.311450817066,
-78837.79087023786,
-26279.67592282737
]
]
},
"unit" : "km"
}
Update 2:
As discussed below the planet 'keys' are not a fixed set. So actually this should be handled as a dictionary. To do something like this you can use a 'hack' by using the setValue forKey to populate a dictionary. For doing this you would need a data model like this:
class MyObject: EVObject {
var date: NSNumber?
var results: Result?
var unit: String?
}
class Result: EVObject {
var planets = [String: [[NSNumber]]]()
// This way we can solve that the JSON has arbitrary keys
internal override func setValue(value: AnyObject!, forUndefinedKey key: String) {
if let a = value as? [[NSNumber]] {
planets[key] = a
return
}
NSLog("---> setValue for key '\(key)' should be handled.")
}
}
You do have to be aware that if you want to create json for this, that you will have an extra level in your hierarchy for planets. If you don't want this, then there is a workaround possible by changing the results property to String: [[NSNumber]] You would then also need to implement the EVCustomDictionaryConverter. See the workaround unit tests to see how that would work.
I have a website with JsRender and a JSON file.
My JSRender code:
{{for ~getModel(cards)}}
{{:id}}
{{/for}}
My JSON file:
{
"alpha": {
"cards": [{
"id": "alpha-01"
}, {
"id": "alpha-02"
}, {
"id": "alpha-03"
}]
},
"beta": {
"cards": [{
"id": "beta-01"
}, {
"id": "beta-02"
}]
}
}
In {{for ~getModel(cards)}} is cards, a suffix.
My JsRender helper concatenates a prefix and a suffix and the result is a string.
This string should be my array for the for loop. The suffix is a dynamic part, a parameter from the URL (?model=alpha)
The for loop should run through the array alpha.cards -> {{for ~getModel(alpha.cards)}}
But when I concate the dynamic part and the suffix, the return value is a string, and the for loop doesn't work. It seems the value (return) for the helper must be an array.
Is that right or is there a another solution for the problem?
Yes - you need to return an array. JsRender renders against javascript objects and arrays (typically a hierarchy of objects and arrays). If your string is a JSON string you need to convert/eval first to produce the corresponding object or array...
I have a document in mongodb with 2 level deep nested array of objects that I need to update, something like this:
{
id: 1,
items: [
{
id: 2,
blocks: [
{
id: 3
txt: 'hello'
}
]
}
]
}
If there was only one level deep array I could use positional operator to update objects in it but for second level the only option I've came up is to use positional operator with nested object's index, like this:
db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}})
This approach works but it seems dangerous to me since I'm building a web service and index number should come from client which can send say 100000 as index and this will force mongodb to create an array with 100000 indexes with null value.
Are there any other ways to update such nested objects where I can refer to object's ID instead of its position or maybe ways to check if supplied index is out of bounds before using it in query?
Here's the big question, do you need to leverage Mongo's "addToSet" and "push" operations? If you really plan to modify just individual items in the array, then you should probably build these arrays as objects.
Here's how I would structure this:
{
id: 1,
items:
{
"2" : { "blocks" : { "3" : { txt : 'hello' } } },
"5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } }
}
}
This basically transforms everything in to JSON objects instead of arrays. You lose the ability to use $push and $addToSet but I think this makes everything easier. For example, your query would look like this:
db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})
You'll also notice that I've dumped the "IDs". When you're nesting things like this you can generally replace "ID" with simply using that number as an index. The "ID" concept is now implied.
This feature has been added in 3.6 with expressive updates.
db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )
The ids which you are using are linear number and it has to come from somewhere like an additional field such 'max_idx' or something similar.
This means one lookup for the id and then update. UUID/ObjectId can be used for ids which will ensure that you can use Distributed CRUD as well.
Building on Gates' answer, I came up with this solution which works with nested object arrays:
db.objects.updateOne({
["items.id"]: 2
}, {
$set: {
"items.$.blocks.$[block].txt": "hi",
},
}, {
arrayFilters: [{
"block.id": 3,
}],
});
MongoDB 3.6 added all positional operator $[] so if you know the id of block that need update, you can do something like:
db.objects.update({'items.blocks.id': id_here}, {'$set': {'items.$[].blocks.$.txt': 'hi'}})
db.col.update({"items.blocks.id": 3},
{ $set: {"items.$[].blocks.$[b].txt": "bonjour"}},
{ arrayFilters: [{"b.id": 3}] }
)
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#update-nested-arrays-in-conjunction-with
This is pymongo function for find_one_and_update. I searched a lot to find the pymongo function. Hope this will be useful
find_one_and_update(filter, update, projection=None, sort=None, return_document=ReturnDocument.BEFORE, array_filters=None, hint=None, session=None, **kwargs)
Example
db.pymongo_object.find_one_and_update( filter = {'id' : 1}, update= {$set: {"items.$[array1].blocks.$[array2].txt": "hi"}}, array_filters =[{"array1.id" :2}, {"array2.id": 3}])
Also see pymongo documentation.