nodejs json.stringify a 1gb object running out of memory - json

I'm trying to json.stringify a 1 gb object so that I can write it to disk. I get FATAL ERROR: JS Allocation failed - process out of memory
What can I do to stringify successfully?

You can stringify bit by bit manually: if y is a key of x, then JSON.stringify(y) + ":" + JSON.stringify(x[y]) gives you one segment.
Using fs.appendFileSync, for example, you can use:
var output = "out.json";
fs.writeFileSync(output, "{");
var first = true;
for(var y in x) {
if(x.hasOwnProperty(y)) {
if(first) first = false;
else fs.appendFileSync(output, ",");
fs.appendFileSync(output, JSON.stringify(y) + ":" + JSON.stringify(x[y]))
}
}
fs.appendFileSync(output, "}");
You can also use a Write Stream

Extended with Object, Array checker
var first, y, i$, ref$, len$, toString$ = {}.toString;
switch (toString$.call(x).slice(8, -1)) {
case 'Object':
fs.writeFileSync(output, '{');
first = true;
for (y in x) {
if (x.hasOwnProperty(y)) {
if (first) {
first = false;
} else {
fs.appendFileSync(output, ',');
}
fs.appendFileSync(output, JSON.stringify(y) + ':' + JSON.stringify(x[y]));
}
}
fs.appendFileSync(output, '}');
break;
case 'Array':
fs.writeFileSync(output, '[');
first = true;
for (i$ = 0, len$ = (ref$ = x).length; i$ < len$; ++i$) {
y = ref$[i$];
if (first) {
first = false;
} else {
fs.appendFileSync(output, ',');
}
fs.appendFileSync(output, JSON.stringify(y));
}
fs.appendFileSync(output, ']');
break;
default:
fs.writeFileSync(output, JSON.stringify(x));
}

Related

Generate Random Mathematical Functions

This is kind of a weird question, and might not be entirely appropriate for Stack Overflow, but I couldn't find anything about it online, so here it is...
Is there a way (or what is the best way) to generate random mathematical functions? By this I don't mean that I want a function that generates a random number (line an RNG), but rather I want to dynamically create some function which which maps one or more real inputs from a domain to a single output using some mutate-able rules.
For example, in the simplest case, I could just generate a function of the form f(x1,x2) -> Y by applying a random operator to x1 and x2. For example f could be:
f = x1 + x2
or f = x1 - x2
or f = x1 * x2
etc...
However, I would like to be able to include more complex formulas including trigonometry, power functions, pseudorandom constants, possibly some calculus functions, etc... Obviously, I cant just concatenate different chunks in a completely random way, since these functions always need to always have valid syntax.
This isn't for anything crypto-related so it doesnt have to be perfect, but the more entropy the better. It would also be great if there is an easy way to keep track of what operations are being preformed and mutate them.
I'm not sure if anyone has any insights on this, or if it even made sense, but thank you anyway
I would suggest that you try to generate random expression trees; pseudocode (somewhat Scala-inspired) for that might look something like this:
NVars = 2
def generateTree(level) = {
if (level > 100) { generateVarref() }
else {
val choice = randomChoice(4)
switch (choice) {
case 0 => generateVarref()
case 1 => generateConstant()
case 2 => generateUnary(level + 1)
case 3 => generateBinary(level + 1)
}
}
}
def generateVarref() = {
val c = randomChoice(NVars)
VarRef(c)
}
def generateConstant() = {
Number(randomChoice(100))
}
def generateUnary(level) = {
val c = randomChoice(6)
val subexpr = generateTree(level)
switch (c) {
case 0 => Negate(subexpr)
case 1 => Sin(subexpr)
// etc. More unary functions here
}
}
def generateBinary(level) = {
val c = randomChoice(4)
val sub1 = generateTree(level)
val sub2 = generateTree(level)
switch (c) {
case 0 => Plus(sub1, sub2)
case 1 => Minus(sub1, sub2)
case 2 => Times(sub1, sub2)
case 3 => Divide(sub1, sub2)
}
}
Where Plus, Varref, etc are constructors for an expression type that implements a method that will then allow you to evaluate the expression at given values.
Let's assume your functions have 2 variables x1 and x2 (if this assumption is too restrictive just adapt my answer to n variables x1, ..., xn.)
[Start] Generate random polynomial functions
This would entail
modeling polynomials in 2 variables (x1 and x2)
implementing the evaluation of polynomials on (any) particular values of the variables
generating random polynomial functions by taking a random degree (up to a certain max) and random coefficients (inside a given interval)
[Compose] Enable Function Composition
This would entail
implementing the composition of functions so that if, say f, g and h are functions in your model (randomly generated or not), then f(g,h) is also a function in your model.
[Enrich] Add new function families to your model
Here you have to consider (and implement) other types of functions to the one you already have (polynomial): rational, trigonometric, logarithmic, exponential, etc. For every new type, you will have to model them and also, to implement a way of generating random instances of them (much as you did for the polynomials.)
[Generate] Create random functions combining all of the above
Choose some types randomly
For every type, generate a random instance
Compose all the types into a final result.
[Iterate] Go to [Enrich] and add new types of functions
Ditto.
Thanks everyone for the help. What I ended up doing was something along the lines of a parse tree, recursively generating new nodes with 2, 1, or 0 children (for binary or unary operators or constants). You could cap depth by checking Node.getDepth(). Below is some JavaScript code showing this process. I'm not sure how useful it will be but it works pretty much how I had envisioned.
'use strict';
var print = console.log;
function randint(a, b) {
return Math.floor((Math.random() * (b + 1 - a)) + a);
}
function Node(parentNode, numberOfVars,
mode, weight, method, numberOfChildren, varIndex, value) {
this.mode = mode ? mode : randint(0, 3);
this.parent = parentNode;
this.weight = weight ? weight : 1;
if (this.mode == 0) { //constant
this.value = value ? value : 1;
} else if (this.mode == 1) { //variable
this.varIndex = varIndex ? varIndex : randint(0, numberOfVars - 1);
} else if (this.mode == 2) { //binary
this.method = method ? method : Node.binary[randint(0, Node.binary.length - 1)];
} else if (this.mode == 3) { //unary
this.method = method ? method : Node.unary[randint(0, Node.unary.length - 1)];
}
if (numberOfChildren) {
this.children = new Array(numberOfChildren);
} else {
this.children = [];
if (this.mode == 2) { //binary
this.children = [new Node(this, numberOfVars),
new Node(this, numberOfVars)
];
} else if (this.mode == 3) { //unary
this.children = [new Node(this, numberOfVars)];
}
}
//Methods
this.execute = function(top_level_variables) {
print("executing " + this.mode);
var inputs = [];
this.children.forEach(function(child, index) {
print("child index " + index);
inputs.push(child.execute(top_level_variables) * child.weight);
});
print(" inputs = " + inputs);
if (this.mode == 0) {
print(" mode == 0");
return this.constant();
}
if (this.mode == 1) {
print(" mode == 1");
return this.variable(top_level_variables);
}
if (this.mode == 2) {
print(" mode == 2");
return this.method(inputs[0], inputs[1]);
}
if (this.mode == 3) {
print(" mode == 3");
return this.method(inputs[0]);
}
};
var getIndent = function(indent) {
var str = "";
if (indent === 0)
return str;
for (var i = 0; i < indent; i++) {
str += " | ";
}
return str;
};
this.getTree = function(indent) {
if (this.mode == 0) {
print(getIndent(indent) + "(" + this.value + ")");
} else if (this.mode == 1) {
print(getIndent(indent) + "x[" + this.varIndex + "]");
} else if (this.mode == 2) {
print(getIndent(indent) + this.method.name);
this.children[0].getTree(indent + 1);
this.children[1].getTree(indent + 1);
} else if (this.mode == 3) {
print(getIndent(indent) + this.method.name);
this.children[0].getTree(indent + 1);
}
};
this.getStr = function() {
if (this.mode == 0) {
return this.value;
} else if (this.mode == 1) {
return "x[" + this.varIndex + "]";
} else if (this.mode == 2) {
return this.method.name + "( " + this.children[0].getStr() + ", " + this.children[1].getStr() + " )";
} else if (this.mode == 3) {
return this.method.name + "( " + this.children[0].getStr() + " )";
}
};
}
Node.binary = [
function add(a, b) {
return a + b
},
function multiply(a, b) {
return a * b
},
function power(a, b) {
return Math.pow(a, b)
}
];
Node.unary = [
function sin(a) {
return Math.sin(a)
}
];
Node.prototype.constant = function() {
return this.value
};
Node.prototype.variable = function(variables) {
return variables[this.varIndex]
};
//Test
var a = new Node(null, 2, 2);
a.getTree(0);
print(a.getStr())
print(a.getDepth());
var b = a.execute([1, 3]);
print(b);

AS3 array to clean up long code?

I would like a better way to write this possibly using an array but I have been unsuccessful. See my code below. I need to add more details to post this but i can't think of more to say. I suppose I eventually need to have to set up a row of btnA show both B and C simultaneously as well. That would also be helpful.
I have a chart that either turns on a square or turns it off when clicked, for example btn3 toggles the visibility of checkMark3, works as written, but when I have 50 or 60 options of clicking the code is exhausting to write and becomes unruly
btnB1.addEventListener (MouseEvent.CLICK, showB1);
function showB1(event:MouseEvent) {
if (checkMarkB1.alpha == 1){
checkMarkB1.alpha = 0;} else {checkMarkB1.alpha = 1}
}
btnB2.addEventListener (MouseEvent.CLICK, showB2);
function showB2(event:MouseEvent) {
if (checkMarkB2.alpha == 1){
checkMarkB2.alpha = 0;} else {checkMarkB2.alpha = 1}
}
btnB3.addEventListener (MouseEvent.CLICK, showB3);
function showB3(event:MouseEvent) {
if (checkMarkB3.alpha == 1){
checkMarkB3.alpha = 0;} else {checkMarkB3.alpha = 1}
}
btnB4.addEventListener (MouseEvent.CLICK, showB4);
function showB4(event:MouseEvent) {
if (checkMarkB4.alpha == 1){
checkMarkB4.alpha = 0;} else {checkMarkB4.alpha = 1}
}
btnC1.addEventListener (MouseEvent.CLICK, showC1);
function showC1(event:MouseEvent) {
if (checkMarkC1.alpha == 1){
checkMarkC1.alpha = 0;} else {checkMarkC1.alpha = 1}
}
btnC2.addEventListener (MouseEvent.CLICK, showC2);
function showC2(event:MouseEvent) {
if (checkMarkC2.alpha == 1){
checkMarkC2.alpha = 0;} else {checkMarkC2.alpha = 1}
}
btnC3.addEventListener (MouseEvent.CLICK, showC3);
function showC3(event:MouseEvent) {
if (checkMarkC3.alpha == 1){
checkMarkC3.alpha = 0;} else {checkMarkC3.alpha = 1}
}
btnC4.addEventListener (MouseEvent.CLICK, showC4);
function showC4(event:MouseEvent) {
if (checkMarkC4.alpha == 1){
checkMarkC4.alpha = 0;} else {checkMarkC4.alpha = 1}
}
Add all your buttons to an array, and all your checkMarks to another array. Make sure that the order of the items in the array means that the position of each button in the buttons array corresponds with the position of its associated checkMark in the checkMarks array.
//add an event listener to all buttons
for(var i:uint=0; i<buttons.length; i++){
buttons[i].addEventListener(MouseEvent.CLICK, showBox);
}
//showBox function
function showBox(evt:MouseEvent):void{
for(var a:uint = 0; a<buttons.length; a++){
if (evt.target == buttons[a]){
if(checkMark[a].alpha == 1){
checkMark[a].alpha = 0;
} else {
checkMark[a].alpha = 1;
}
}
}
}
This should mean you can just add as many buttons and checkMarks as you like to the array, as long as you add them in the right order and always have a checkMark for every button.
Trex had it I just needed to get it right, this dynamically makes the names and sets the visibility of the check marks. So for a grid that has many check marks to use and turn on and off this is what I ended up with,
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
// The two parameters below will be used to dynamically generate the clipinstance names
var letters: Array = ['A', 'B', 'C', 'D', 'E'];
var index: int = 9;
for (var i: int = 1; i <= index; i++) {
// we keep a reference of the movie clip because the scope is lost in the anonymous event listener
var mc = this;
// instead of setting checkMarkE9.visible = false; we do all of this dynamically
trace('Updating visibility of : ' + 'checkMark' + letters[1] + i);
this['checkMark' + letters[1] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[2] + i);
this['checkMark' + letters[2] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[3] + i);
this['checkMark' + letters[3] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[4] + i);
this['checkMark' + letters[4] + i].visible = false;
// dynamically adding event listeners
this['btn' + letters[0] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
var btnIndex: String = getLastLetter(e.currentTarget.name);
trace('Updating visibility of : ' + 'checkMark' + letters[1] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[2] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[3] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[4] + btnIndex);
mc['checkMark' + letters[1] + btnIndex].visible = true;
mc['checkMark' + letters[2] + btnIndex].visible = true;
mc['checkMark' + letters[3] + btnIndex].visible = true;
mc['checkMark' + letters[4] + btnIndex].visible = true;
});
// dynamically add event listeners for cells
this['btn' + letters[1] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[1] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[2] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[2] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[3] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[3] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[4] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[4] + getLastLetter(e.currentTarget.name)]);
});
}
// switches a display item visiblity
function switchVisibility(display: DisplayObject): void {
display.visible = !display.visible;
}
// get the last letter of a string
function getLastLetter(str: String): String {
return str.substr(str.length - 1, str.length);
}

What is the right way to compare as3 objects using hamcrest

I'm trying to compare two objects to see if they are the same using hamcrest for flex-unit, but when the object has sub objects, it just throws an error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
I want it to do an assertThat(..., hasProperties(...)); on the sub object.
Is there a way to get that or should i create a custom matcher?
EDIT
An example of the object structure i want to test:
var expected:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
var objectUnderTest:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
assertThat("should be the same", objectUnderTest, hasProperties(expected));
since the expected and objectUnderTest have the same structure, the test should pass, but is returning the error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
Also, if there is a way to compare two JSON strings will be fine too.
EDIT2
This is my final version after djib help:
package com
{
public function assertEqualsObjects(message:String, object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2, message + ": object") && compare(object2, object1, message + ": extra"));
}
}
import org.flexunit.asserts.fail;
function compare(object1:Object, object2:Object, parent:String):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (!object2.hasOwnProperty(s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: undefined");
return false;
}
if (!compare(object1[s], object2[s], parent + "." + s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: " + object2[s]);
return false;
}
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
{
fail(parent + " expected: " + object1 + " but was: " + object2);
return false;
}
return true;
}
I've put this code together. Recursion is the key ^^
// our two objects to compare ...
var obj1 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
var obj2 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
trace(isSame(obj1, obj2)); // -> true
function isSame(object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2) && compare(object2, object1));
}
function compare(object1:Object, object2:Object):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (object2[s] == undefined)
return false;
if (!compare(object1[s], object2[s]))
return false;
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
return false;
return true;
}

jQuery click() each() unique?

I want to have multiple span.play without IDs which can be clicked and play some audio file.
Problem: Display the duration on only the current file $(this)
$('.play').each(function() {
$(this).append('<span class="playIcon"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Fairytale_player_play.png/14px-Fairytale_player_play.png"></span><span class="playDur"></span>');
$(this).click(function() {
var file = this.firstChild;
if (file.paused != false) {
//+ stop all others before playing new one
file.play();
} else {
file.pause();
}
file.addEventListener("timeupdate", function() {
var len = file.duration,
ct = file.currentTime,
s = parseInt(ct % 60),
m = parseInt((ct / 60) % 60);
if (s < 10) {
s = '0' + s;
}
$(".playDur").html(' (' + m + ':' + s + ')');
if (ct == len) {
$(".playDur").html('');
}
}, false);
});
});
Test:
http://jsfiddle.net/sQPPP/
http://jsfiddle.net/sQPPP/1/ - using $(this).children( ".foo" )
You need to save .play jQuery object in a variable, as this changes within the addEventListener callback.
http://jsfiddle.net/sQPPP/2/
$('.play').each(function(index) {
var $play = $(this);
$play.append('<span class="playIcon"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Fairytale_player_play.png/14px-Fairytale_player_play.png"></span><span class="playDur"></span>');
$play.click(function() {
var file = this.firstChild;
if (file.paused != false) {
//+ stop all others before playing new one
file.play();
} else {
file.pause();
}
file.addEventListener("timeupdate", function() {
var len = file.duration,
ct = file.currentTime,
s = parseInt(ct % 60),
m = parseInt((ct / 60) % 60);
if (s < 10) {
s = '0' + s;
}
$play.children( ".playDur" ).html(' (' + m + ':' + s + ')');
if (ct == len) {
$play.children( ".playDur" ).html('');
}
}, false);
});
});​

CRM 2011: Getting entity with Javascript

I am working on some CRM 2011 Online customisations and I need to get an entity using javascript.
The entity I need will be based on the ID value of another field (a Contact entity) - this Contact ID I can get fine.
The entity I want is a custom entity. There may be multiple matches based on the Contact ID so I just want to get the first one in the list (order not important)
So far I have looked into a few ways to do this...
OData - I couldn't find enough examples on this as to what query expressions I can create, also I don't know if/how to make this work for custom entities
FetchXML - I can create a nice FetchXML query using the built-in "advanced find" too and would be happy to call this from javascript if anyone can help? I found one promising answer here but I could not see how the "results" return data was being set (Service.Fetch function)
SOAP Request - First thing I tried is a similar method as I could have done in CRM 4 but this does not seem to work. Although the request executes, my result data just seems to be empty. This is all I have code for so if any one can spot a problem with the code below then that would be great.
EDIT: I have spotted some redundant query data (I had removed link opening tags but left closing tags) - since removing this I now get XML result data... however, the where clause does not seem to apply (just get list of all entities)
var xml = "<?xml version='1.0' encoding='utf-8'?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
"<soap:Body>" +
"<RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
"<query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
"<q1:EntityName>new_vehicle</q1:EntityName>" +
"<q1:ColumnSet xsi:type='q1:ColumnSet'>" +
"<q1:Attributes>" +
"<q1:Attribute>new_vehicleid</q1:Attribute>" +
"<q1:Attribute>new_primarydriver</q1:Attribute>" +
"<q1:Attribute>statuscode</q1:Attribute>" +
"<q1:Attribute>new_registration</q1:Attribute>" +
"</q1:Attributes>" +
"</q1:ColumnSet>" +
"<q1:Distinct>false</q1:Distinct>" +
"<q1:Conditions>" +
"<q1:Condition>" +
"<q1:AttributeName>new_primarydriver</q1:AttributeName>" +
"<q1:Operator>Equal</q1:Operator>" +
"<q1:Values>" +
"<q1:Value xmlns:q2='http://microsoft.com/wsdl/types/' xsi:type='q2:guid'>" +
customerID +
"</q1:Value></q1:Values></q1:Condition>" +
"</q1:Conditions>" +
"</query></RetrieveMultiple>" +
"</soap:Body></soap:Envelope>";
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);
var result = xmlHttpRequest.responseXML.xml;
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async = false;
doc.loadXML(result);
var id = doc.selectSingleNode("//new_vehicleid");
var registration = doc.selectSingleNode("//new_registration");
if(id == null)
return null;
var vehicle = new Array();
value[0] = new Object();
value[0].id = id;
value[0].name = registration;
value[0].entityType = "new_vehicle";
return vehicle;
Sorry about the big code post but hopefully somebody who has a better understanding can help
Firstly, thanks to GlennFerrieLive for his answer post. The samples I found with the Dynamics CRM 2011 SDK (well just one in particular) really helped and the JSON parser included was perfect for the job!
I am posting this answer to give a full example of how I did it with some important comments to pay attention to which may not be so obvious from the SDK examples.
Get selected ID value from lookup field
The aim of my task was to use javascript to get set a lookup field, based on the selected data of another lookup entity. The entity to set is "new_vehicle" and the entity to query on is "customer".
First job is to get the ID value of the contact lookup field...
var customerItem = Xrm.Page.getAttribute("customerid").getValue();
var customerID = customerItem[0].id;
Querying an entity using an ID
Next is the part where I used the customerID value to find the vehicle that is currently assigned to them (the entity I want to use to set a lookup field).
First problem I found was that when querying with OData, the ID value does not seem to work with curly brackets {} - so these need to be removed...
customerID = customerID.replace('{', '').replace('}', '');
Next we get the oDataPath...
var oDataPath = Xrm.Page.context.getServerUrl() + "/xrmservices/2011/organizationdata.svc";
Then we can construct the OData query...
var filter = "/new_vehicleSet?" +
"$select=new_vehicleId,new_Registration" +
"&$filter=new_PrimaryDriver/Id eq (guid'" + customerID + "')" +
"&$orderby=new_LastAllocationDate desc" +
"&$top=1";
NOTE: There are a couple of important things to note here...
When using a guid value you must explicitly say it is a guid using (guid'xxx')
When filtering by a lookup entity (e.g. new_PrimaryDriver) you must append the value to query (e.g. Id) - this results in new_PrimaryDriver/Id
Once we have the query setup we can request the data as follows...
var retrieveRecordsReq = new XMLHttpRequest();
retrieveRecordsReq.open("GET", oDataPath + filter, true);
retrieveRecordsReq.setRequestHeader("Accept", "application/json");
retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
retrieveRecordsReq.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
var retrievedRecords = JSON.parse(retrieveRecordsReq.responseText).d;
if(retrievedRecords.results.length > 0)
{
var vehicle = retrievedRecords.results[0];
SetLookup("new_replacedvehicle", vehicle.new_vehicleId, vehicle.new_Registration, "new_vehicle");
}
}
}
};
retrieveRecordsReq.send();
Note that this is an asynchronous call and the onreadystatechange function will be processed upon completion, in this function we do a couple of checks to see if it was a success and the we parse the resulting JSON data - the JSON.Parse function has been included at the bottom of this post (but is available from the SDK)
Setting a lookup field using the entity queried above
The other function to make note of here is SetLookup which is just a simple helper function I added to set a lookup field. This is as follows...
function SetLookup(fieldName, idValue, textValue, typeValue)
{
var value = new Array();
value[0] = new Object();
value[0].id = idValue;
value[0].name = textValue;
value[0].typename = typeValue;
Xrm.Page.getAttribute(fieldName).setValue(value);
}
JSON parse function
This is the JSON helper function that was used in the above code (JSON.parse), pasted as it was found in the SDK...
if (!this.JSON) { this.JSON = {}; } (function () { function f(n) { return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } if (typeof rep === 'function') { value = rep.call(holder, key, value); } switch (typeof value) { case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === '[object Array]') { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { var i; gap = ''; indent = ''; if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } return str('', { '': value }); }; } if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { var j; function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '#').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; } } ());