This in relation to my older ticket here!
But now I need to get more advanced. I need to get only certain attributes and their values (from the 1st Response JSON) to create another JSON (and some values to be replaced in new JSON).
I.e. in the Response JSON below, I need to go through all "Items" (and I do not know in advance how many those can be), and get only Id + value, and Status+value for each of them. Then to build another new JSON, where the top attribute will be called Products instead of Variations, and contain only Id+value and Status+*NewValue*.
1st Response JSON:
"Variations":[
{
"ItemIds":[
"xxx"
],
"Items":[
{
"Id":"67-V1",
"GuId":"xxx",
"Type":"Unit",
"Status":"Active"
}
],
"Name":"VAR 1",
"Id":"67-V1"
},
{
"ItemIds":[
"yyy"
],
"Items":[
{
"Id":"67-V2",
"GuId":"yyy",
"Type":"Unit",
"Status":"Active"
}
],
"Name":"VAR 2",
"Id":"67-V2"
},
{
"ItemIds":[
"zzz"
],
"Items":[
{
"Id":"67-V3",
"GuId":"zzz",
"Type":"Unit",
"Status":"Active"
}
],
"Name":"VAR 3",
"Id":"67-V3"
}
],
"ItemIds":[
],
"Items":[
],
"Name":"MAINP",
"Id":"67",
"Color":null
}
New JSON I would like to create:
{
"Products":[
{
"Id":"67-V1",
"Status":"NonActive"
},
{
"Id":"67-V2",
"Status":"NonActive"
},
{
"Id":"67-V3",
"Status":"NonActive"
}
]
}
I have made following code:
var jsonData = pm.response.json();
var newData;
var newDataGroup = "";
function replaceValues() {
_.each(jsonData.Variations, (arrayItem) => {
_.each(arrayItem.Items, (item) => {
if(item.Status !== "NonActive") {
item.Status = "NonActive";
console.log("arrayItem " + item.Status);
}
newData = "{ \"Id\":\"" + item.Id + "\", " + " \"Status\":\"" + item.Status + "\"},";
newDataGroup = newDataGroup + newData;
});
});
newDataGroup = "{ \"Products\": [ " + newDataGroup + " ] }";
}
pm.test("Run Replace", replaceValues ());
console.log("newDataGroup Final: " + newDataGroup);
var newJson = JSON.parse(newDataGroup);
console.log("newJson: " + newJson);
Here is my outcome (based on the code above), but how to deal with the last , there?
{
"Products":[
{
"Id":"67-V1",
"Status":"NonActive"
},
{
"Id":"67-V2",
"Status":"NonActive"
},
{
"Id":"67-V3",
"Status":"NonActive"
},
]
}
Seems like here is the final code that will do the trick. While most likely, not the most elegant but does the job. If anyone can suggest the more elegant way, would be appreciated.
var jsonData = pm.response.json();
var newData;
var newDataGroup = "";
function replaceValues() {
_.each(jsonData.Variations, (arrayItem) => {
_.each(arrayItem.Items, (item) => {
if(item.Status !== "NonActive") {
item.Status = "NonActive";
}
newData = "{ \"Id\":\"" + item.Id + "\", " + " \"Status\":\"" + item.Status + "\"},";
newDataGroup = newDataGroup + newData;
});
});
newDataGroup = newDataGroup.slice(0, -1);
newDataGroup = "{ \"Products\": [ " + newDataGroup + " ] }";
}
pm.test("Run Replace", replaceValues ());
var newJson = JSON.parse(newDataGroup);
Related
Given the following DynamoDB document:
{
"myobject" : {"foo" : "bar"},
"mylist" : [{"some" : "stuff}]
}
My goal is to update this document to get the following result:
{
"myobject" : {"foo" : "bar"},
"mylist" : [{"some" : "stuff}, {"foo" : "bar"}]
}
My request's params look like this:
let params = {
TableName: doctorSlotsTable,
Key: {
hashKey: hash,
rangeKey: range
},
UpdateExpression: 'SET mylist = list_append(if_not_exists(mylist, :empty_list), [myobject])',
ExpressionAttributeValues : {
':empty_list' : []
},
ReturnValues : "UPDATED_NEW"
};
This obviously does not work because the [ in the list_append triggers a syntax error.
Is there any solution to achieve that without having to get the data in a previous request and add it manually to the list ?
Unfortunately you cannot use an attribute name as an operand to list_append(...) unless that attribute is itself a list. The best you can do I believe would be to store myobject in the proper type up front, and then update it as expected.
Since storage is cheap & network/compute are expensive here, you could even duplicate the data to have one of them in the right form.
Here's a full example, where createTable() and deleteTable() do exactly what you think:
const PK = 'the item';
async function createObjAndList() {
const docClient = new DocumentClient();
const myObject = { foo: "bar" };
const theItem = {
PK,
myObject,
myObjectAsList: [ myObject ],
myList: [ { some : "stuff" } ],
};
const putParams = {
TableName,
Item: theItem
}
await docClient.put(putParams).promise();
console.log(`Put item ${util.inspect(theItem)}`);
}
async function updateListWithObject() {
const docClient = new DocumentClient();
const updateParams = {
TableName,
Key: { PK },
UpdateExpression: `SET #myList = list_append(if_not_exists(#myList, :emptyList), #myObjectAsList)`,
ExpressionAttributeNames: {
'#myList': 'myList',
'#myObjectAsList': 'myObjectAsList',
},
ExpressionAttributeValues: {
':emptyList': [],
}
}
await docClient.update(updateParams).promise();
console.log(`Updated list to include object`);
}
async function getObjAndList() {
const docClient = new DocumentClient();
const results = await docClient.get({ TableName, Key: { PK }}).promise();
console.log(`Item is now: ${util.inspect(results.Item)}`);
}
if (module === require.main) {
(async () => {
try {
await createTable();
await createObjAndList()
await updateListWithObject();
await getObjAndList();
} catch (err) {
console.log(`Error: ${err.message}`);
} finally {
await deleteTable();
}
})();
}
The output from this is:
Put item {
PK: 'the item',
myObject: { foo: 'bar' },
myObjectAsList: [ { foo: 'bar' } ],
myList: [ { some: 'stuff' } ]
}
Updated list to include object
Item is now: {
myList: [ { some: 'stuff' }, { foo: 'bar' } ],
myObject: { foo: 'bar' },
PK: 'the item',
myObjectAsList: [ { foo: 'bar' } ]
}
Im implementing a mongodb search.
The search performs a find on field values:
[{
value: "my.string.here"
}, {
value: "my other here"
}{
...
}]
When i enter "my" both entries are found. What have my query to look like to ignore the dots on the first entry? So when i enter "my string" the first element gets returned?
Actually it works only when i enter "my.string" which is not nice.
let limit = Number(req.query.limit || 100);
let skip = Number(req.query.skip || 0);
collection.find({
$or: [{
value: new RegExp(req.body.search, "gi")
}, {
tags: {
$in: req.body.search.split(",").map((val) => {
return new RegExp(val, "gi")
})
}
}]
}).skip(skip).limit(limit).toArray((err, result) => {
if (err) {
res.status(500).json(err);
} else {
res.status(200).json(result);
}
});
EDIT:
A solution could look like this:
let query = {
$or: [{
name: new RegExp(req.body.search, "gi")
}, {
tags: {
$in: req.body.search.split(",").map((val) => {
return new RegExp(val, "gi")
})
}
}, {
name: new RegExp(req.body.search.split(' ').join('.'), "gi")
}, {
name: new RegExp(req.body.search.split(' ').join('_'), "gi")
}, {
name: new RegExp(req.body.search.split(' ').join('-'), "gi")
}]
};
But i find it ugly and not elegant. Is there a better way to do this ?
I have a table that has userId as the PK and a single attribute called userToken.
I have written a batchGet() function to return all the userTokens for specific userIds, however it returns it like this:
[ { userToken: '1234' },
{ userToken: '5678' } ]
I'd like it to just return the values since I already know what the attribute name will be:
['1234', '5678']
How would I go about doing so?
const params = {
RequestItems: {
UserTokens: {
Keys: userIds,
AttributesToGet: [
'userToken'
]
}
}
};
db.batchGet(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log(data.Responses);
sendNotifications(data.Responses);
}
});
DynamoDB always returns the attribute name and value.
You can easily filter this on the client side.
val = [ { userToken: '1234' }, { userToken: '5678' } ];
reducer = (accumulator, currentVal) => {
accumulator.push(currentVal.userToken);
return accumulator;
}
console.log(val.reduce(reducer, []));
I'm using Typeahead version 0.10.5. It's working for english words but it's not working for each word written in cyrrilic. Some words written in cyrillic are shown, but others aren't. What is this due to?
I'm using it like this:
$('#edicode').typeahead({
source: function(query, process){
CallAPI("GET", "/companies/get/" + query + "/like", function (data) {
var sourcedata = new Array();
var jsonData = JSON.parse(data);
var count = 0;
$.each(jsonData, function(jsonId) {
sourcedata.push(jsonData[jsonId].CODE + ' / ' + jsonData[jsonId].NAME);
selectedItems[jsonData[jsonId].CODE] = JSON.stringify(jsonData[jsonId]);
count++;
});
if(count <= 0)
{
$('#company_name').val('');
$('#company_name').prop('readonly', false);
}
console.log(sourcedata);
return process(sourcedata);
});
},
updater: function (item) {
var info = item.split(" / ");
var company = jQuery.parseJSON(selectedItems[info[0]]);
$('#EDICode').val(company.CODE);
return company.CODE + '/ ' + company.NAME ;
},
name: 'Company',
displayKey: 'value',
minLength: 2,
maxItem: 15,
accent: true,
hint: true
}).blur(function(){
});
Took 1 hour to find:
open bootstrap-typeahead.js (not minified)
find:
matcher: function (item) {
return ~item.toLowerCase().indexOf(this.query.toLowerCase());
},
change to:
matcher: function (item) {
var x=item.toLowerCase().indexOf(this.query.toLowerCase());;
if(x==-1)
x=0;
return ~x
},
I'm writing unit tests for my yeoman generator.
I've noticed that mockPrompt does not use default values for my prompt values.
For instance, I have a version parameter that defaults to 0.0.1, but unless I specify a value for version in my test, the result is an empty string.
Is this by design or am I doing something wrong.
This is my prompt function from index.js:
var prompts = [{
name: 'libName',
message: 'What do you want to call your lib?'
},{
name: 'libVersion',
message: 'What version would you like to set?',
default: "0.0.1"
},{
name: 'libDesc',
message: 'Describe your lib:'
},{
name: 'authorName',
message: 'What is your full name?'
},{
name: 'angularVersion',
message: 'Enter angular version:',
default: '1.2.7'
},{
name: 'ngResourceRequired',
message: 'Do you require ngResource module?',
type:'confirm',
default: false
}];
this.prompt(prompts, function (props) {
this.libName = props.libName;
this.libVersion = props.libVersion;
this.libDesc = props.libDesc;
this.authorName = props.authorName;
this.angularVersion = props.angularVersion;
this.ngResourceRequired = props.ngResourceRequired;
cb();
}.bind(this));
And this is my test code:
describe('my-jslib:app', function () {
var jslib;
var appPath = 'customAppPath';
var expected = [
appPath + '/.htaccess',
appPath + '/404.html',
appPath + '/favicon.ico',
appPath + '/robots.txt',
appPath + '/styles/main.scss',
appPath + '/views/main.html',
appPath + '/index.html',
'.bowerrc',
'.editorconfig',
'.gitignore',
'.jshintrc',
'Gruntfile.js',
'package.json',
'bower.json'
];
var mockPrompts = {
libName: "test",
//libVersion: "0.0.1",
angularVersion: "1.2.7",
ngResourceRequired: false
};
var genOptions = {
'appPath': appPath,
'skip-install': true,
'skip-welcome-message': true,
'skip-message': true
};
beforeEach(function (done) {
helpers.testDirectory(path.join(__dirname, 'tmp'), function (err) {
if (err) {
done(err);
}
jslib = helpers.createGenerator(
'my-jslib:app', [
'../../app', [
helpers.createDummyGenerator(), 'mocha:app'
]
],
false,
genOptions
);
helpers.mockPrompt(jslib, mockPrompts);
done();
});
});
it('creates expected files', function (done) {
var expected = [
'.bowerrc',
'.editorconfig',
'.gitignore',
'.gitattributes',
'.jshintrc',
'bower.json',
'Gruntfile.js',
'package.json',
'README.md',
'src/' + mockPrompts.libName + '.js',
'test/spec/' + mockPrompts.libName + '.js',
'test/.jshintrcs',
'test/karma.conf.js'
];
jslib.run({}, function () {
helpers.assertFile(expected);
helpers.assertFileContent('package.json', new RegExp('"name": "' + mockPrompts.libName + '"'));
helpers.assertFileContent('bower.json', new RegExp('"name": "' + mockPrompts.libName + '"'));
helpers.assertFileContent('bower.json', new RegExp('"angular": "' + mockPrompts.angularVersion + '"'));
helpers.assertNoFileContent('bower.json', new RegExp('"angular-resource": "' + mockPrompts.angularVersion + '"'));
done();
});
});
});
Thanks,
Lior
To mock the default prompt you have to omit the variable in the object of the mock.
var mockPrompts = {
libName: "test",
angularVersion: "1.2.7",
ngResourceRequired: false
};
This will trigger the default value for "libVersion"