JOLT to index a field based on the name of another - jolt

Not sure if this is possible in jolt.
We are trying to extract a value whose field name is indexed by another field. Please take a look at the description below.
{
"_src" : {
"SomeName" : 123,
"FName" : "SomeName"
}
}
to
{
"val": "123",
"_src" : {
"SomeName" : 123,
"FName" : "SomeName"
}
}
Any ideas on how approach this, or if this is even possible in JOLT?
Thanks

Using shift spec:
Match on _src
Set value using SomeName
Using syntax #(1,src) which means go up 1 level and copy src, & will get the name of the current element.
[
{
"operation": "shift",
"spec": {
"_src": {
"SomeName": "val",
"#(1,_src)": "&"
}
}
}
]

Related

Set value of string to first element of array

For a given document, I am attempting to set a field (string) as the first element of an array of strings. Consider a collection myPlaces with the following document:
{
"name" : "Place Q",
"images" : [
"foo-1",
"foo-2",
"foo-3"
]
}
I am looking to create the following:
{
"name" : "Place Q",
"images" : [
"foo-1",
"foo-2",
"foo-3"
],
"image" : "foo-1"
}
So in the mongo shell, I execute:
db.myPlaces.update(
{
name: "Place Q"
},
{
$set:
{
image: images.0
}
}
)
This throws the error SyntaxError: missing } after property list which I don't understand. If I enclose the array in quotes "images.0" the value of image is set as "images.0", not "foo-1".
I've been reviewing the Mongodb documentation and see a lot of different examples but not something that makes clear to me what is probably a simple syntax for accessing an array value.
The following query works on MongoDB 4.2, It might not work on previous versions.
db.myPlaces.update(
{
name: "Place Q"
},
[
{
$set: {
image: {
$arrayElemAt: ["$images",0]
}
}
}
]
)
It's also very efficient as it is using $set pipeline provided in MongoDB 4.2+ versions.
Can you try this please :
db.myPlaces.update(
{
name: "Place Q"
},{
$set:
{
image: db.myPlaces.find( { "images.0" } )
}
}
)
Here what you can do is:
Find the document first.
Iterate on that (You must have only one value, but it will work for multiple documents as well)
Update document.
Note:- Efficient for the small records. Bulk record will have lots of traffic on DB.
===== Will work for all version of MongoDB ======
Data Before:
{
"_id" : ObjectId("5d53fda5f5fc3d6486b42fec"),
"name" : "Place Q",
"images" : [
"foo-1",
"foo-2",
"foo-3"
]
}
Query:
db.collection.find({ name: "Place Q" }).forEach(function(document) {
db.collection.update(
{},
{ "$set": { "image": document.images[0] } }
);
})
Data After
{
"_id" : ObjectId("5d53fda5f5fc3d6486b42fec"),
"name" : "Place Q",
"images" : [
"foo-1",
"foo-2",
"foo-3"
],
"image" : "foo-1"
}

How to find nodes with an object that contains a string value

I'm struggling to create a find query that finds nodes that contain "Item1".
{
"_id" : ObjectId("589274f49bd4d562f0a15e07"),
"Value" : [["Item1", {
"Name" : "John",
"Age" : 45
}], ["Item2", {
"Address" : "123 Main St.",
"City" : "Hometown",
"State" : "ZZ"
}]]
}
In this example, "Item1" is not a key/value pair, but rather just a string that is part of an array that is part of a larger array. This is a legacy format so I can't adjust it unfortunately.
I've tried something like: { Value: {$elmemmatch:{$elemmatch:{"Item1"}}}, but that is not returning any matches. Similarly, $regex is not working since it only seems to match on string objects (and the overall object is not a string, but a string in an array in an array).
It seems like you should use the $in or $eq operator to match value.
So try this:
db.collection.find({'Value':{$elemMatch:{$elemMatch:{$in:['Item1']}}}})
Or run this to get the specific Item
db.collection.find({},{'Value':{$elemMatch:{$elemMatch:{$in:['Item1']}}}})
Hope this helps.
var data = {
"_id":"ObjectId('589274f49bd4d562f0a15e07')",
"Value":[
[
"Item1",
{
"Name":"John",
"Age":45
}
],
[
"Item2",
{
"Address":"123 Main St.",
"City":"Hometown",
"State":"ZZ"
}
]
]
}
data.Value[0][0] // 'Item1'
Copy and paste on repl it works.
There was an error on structure ofr your data

Retrieving value of an emedded object in mongo

Followup Question
Thanks #4J41 for your spot on resolution. Along the same lines, I'd also like to validate one other thing.
I have a mongo document that contains an array of Strings, and I need to convert this particular array of strings into an array of object containing a key-value pair. Below is my curent appraoch to it.
Mongo Record:
Same mongo record in my initial question below.
Current Query:
templateAttributes.find({platform:"V1"}).map(function(c){
//instantiate a new array
var optionsArray = [];
for (var i=0;i< c['available']['Community']['attributes']['type']['values'].length; i++){
optionsArray[i] = {}; // creates a new object
optionsArray[i].label = c['available']['Community']['attributes']['type']['values'][i];
optionsArray[i].value = c['available']['Community']['attributes']['type']['values'][i];
}
return optionsArray;
})[0];
Result:
[{label:"well-known", value:"well-known"},
{label:"simple", value:"simple"},
{label:"complex", value:"complex"}]
Is my approach efficient enough, or is there a way to optimize the above query to get the same desired result?
Initial Question
I have a mongo document like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"platform" : "A1",
"available" : {
"Community" : {
"attributes" : {
"type" : {
"values" : [
"well-known",
"simple",
"complex"
],
"defaultValue" : "well-known"
},
[......]
}
I'm trying to query the DB and retrieve only the value of defaultValue field.
I tried:
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
as well as
db.templateAttributes.findOne(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
But they both seem to retrieve the entire object hirarchy like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"available" : {
"Community" : {
"attributes" : {
"type" : {
"defaultValue" : "well-known"
}
}
}
}
}
The only way I could get it to work was with find and map function, but it seems to be convoluted a bit.
Does anyone have a simpler way to get this result?
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
).map(function(c){
return c['available']['Community']['attributes']['type']['defaultValue']
})[0]
Output
well-known
You could try the following.
Using find:
db.templateAttributes.find({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 }).toArray()[0]['available']['Community']['attributes']['type']['defaultValue']
Using findOne:
db.templateAttributes.findOne({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 })['available']['Community']['attributes']['type']['defaultValue']
Using aggregation:
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}},
{"$project": {_id:0, default:"$available.Community.attributes.type.defaultValue"}}
]).toArray()[0].default
Output:
well-known
Edit: Answering the updated question: Please use aggregation here.
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}}, {"$unwind": "$available.Community.attributes.type.values"},
{$group: {"_id": null, "val":{"$push":{label:"$available.Community.attributes.type.values",
value:"$available.Community.attributes.type.values"}}}}
]).toArray()[0].val
Output:
[
{
"label" : "well-known",
"value" : "well-known"
},
{
"label" : "simple",
"value" : "simple"
},
{
"label" : "complex",
"value" : "complex"
}
]

MongoDB aggregation query to split and convert JSON?

I have a JSON file with a horrific data structure
{ "#timestamp" : "20160226T065604,39Z",
"#toplevelentries" : "941",
"viewentry" : [ { "#noteid" : "161E",
"#position" : "1",
"#siblings" : "941",
"entrydata" : [
and entrydata is a list of 941 entries, each of which look like this
{ "#columnnumber" : "0",
"#name" : "$Created",
"datetime" : { "0" : "20081027T114133,55+01" }
},
{ "#columnnumber" : "1",
"#name" : "WriteLog",
"textlist" : { "text" : [ { "0" : "2008.OCT.28 12:54:39 CET # EMI" },
{ "0" : "2008.OCT.28 12:56:13 CET # EMI" },
There are many more columns. The structure is always this:
{
"#columnnumber": "17",
"#name": "PublicDocument",
"text": {
"0": "TMI-1-2005.pdf"
}
}
there's a column number which we can throw away, a #name which is the important part, then one of text, datetime or textlist fields where the value is always this weird subdocument with a 0 key and the actual value.
All 941 entries have the same number of these column entries and the column entry is always the same structure. Ie. if "#columnnumber": "13" has a #name: foo then it'll always be foo and if it has a datetime key then it always will have a datetime key, never a text or textlist. This monster was borne out of a SQL or similar database somewhere at the very far end of the pipeline but I have no access to the source beyond this. The goal is to revert the transformation and make it into something a SELECT statement would produce (except textlist, although I guess array_agg and similar could produce that too).
Is there a way to get 941 separate JSON entries out of MongoDB looking like:
{
$Created: "20081027T114133,55+01",
WriteLog: ["2008.OCT.28 12:54:39 CET # EMI", "2008.OCT.28 12:56:13 CET # EMI"],
PublicDocument: "TMI-1-2005.pdf"
}
is viewentry also a list?
if you do an aggregate on the collection, and $unwind on viewentry.entrydata you will get one document for every entrydata. It should be possible to the do a $project to reformat these documents to produce the output you need
this is a nice challenge,
to get outupt like that:
{
"_id" : "161E",
"field" : [
{
"name" : "$Created",
"datetime" : {
"0" : "20081027T114133,55+01"
}
},
{
"name" : "WriteLog",
"textlist" : {
"text" : [
{
"0" : "2008.OCT.28 12:54:39 CET# EMI"
},
{
"0" : "2008.OCT.28 12:56:13 CET# EMI"
}
] } } ]}
use this aggregation pipelines:
db.chx.aggregate([ {$unwind: "$viewentry"}
, {$unwind: "$viewentry.entrydata"}
,{$group:{
"_id":"$viewentry.#noteid", field:{ $push:{
"name": "$viewentry.entrydata.#name" ,
datetime:"$viewentry.entrydata.datetime",
textlist:"$viewentry.entrydata.textlist" }}
}}
]).pretty()
the next step should be extracting log entries, but I have no idea, as my brain is already fried tonight - so probably I can return later...

Update Object at Specific Array Index in MongoDB

I have a collection of the form
{ id : 1,
data: [ [ { name : "alice" }, { name : "bob" } ],
[ { name : "dan" }, { name : "rob" } ] ] }
and the structure of the array has meaning. How would I update the first element ([0][0]) and set name = "alex". I've seen many questions addressing how to update array elements that match a query but not specific elements. To be clear, after the update, the record should look like this:
{ id : 1,
data: [ [ { name : "alex" }, { name : "bob" } ],
[ { name : "dan" }, { name : "rob" } ] ] }
Assuming, you have created the structure with some purpose, which ideally becomes tougher to query, you could update it by specifying the index explicitly:
db.collection.update({"id":1},{$set:{"data.0.0.name":"alex"}})
If we don't have a fixed position and is known at runtime or Dynamic
then this approach works perfectly
var setObject = {};
setObject["board."+ x +"."+ y] = player;
gamesColl.update({_id: realId},{
$set:setObject
}, function(err,doc){
console.log(err,doc);
});
you can go further!!
if you want to paste indexes as a variable use string template like this
db.collection.update({"id":1},{$set:{[`data.${index}.${index}.name`]:"alex"}})