1

In Delphi, using TMongoWire, I am trying to save off a company profile with a variable number of phone numbers. I wanted the resulting saved JSON to look like:

{"ourID":"XYZ1", 
 "Company":"XYZ Company",
  "Phones": [{"number":"714-999-9999", "type":"business"},
             {"number":"714-987-6533", "type":"cell"}]
}

But I can't seem to figure out how to get the phones into MongoDB. I tried to create the JSON for the phones myself then pass that to the Phones field but what got stored was a string of the JSON, not a JSON array. It looks like:

"Phones":"[{\"Phone\":\"123-456-7890\", \"pType\":\"Home Phone\", \"notes\":\"this is the home phone\"}]"

Any suggestions?

Thanks, Jim

Jim Hunter
  • 95
  • 1
  • 6

2 Answers2

2

I think it was easier than it looked. I just used nested BSON([]) statements and it worked like a champ. The test code looks like this:

  b := BSON(['test','this is a test',
             'Phones', BSON(['number', '1234', 'number','54533'])]);

And the resulting JSON is correct in MongoDB.

Jim Hunter
  • 95
  • 1
  • 6
2

TMongoWire's BSON document is built around variant arrays, So you can use the VarArrayOf function from the Variants unit to make the above document:

BSON(['ourID','XYZ1', 
  'Company','XYZ Company',
  'Phones',VarArrayOf([
    BSON(['number','714-999-9999', 'type','business']),
    BSON(['number','714-987-6533', 'type','cell'])
  ])]);
Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67
  • Thanks, this is a better solution. But I have been doing JavaScript work for so long and having not used BSON until now, I am having a tough time coming up with a function to create the VarArry from my TList of TPhone numbers. The number of phone numbers is undetermined at the time I need to save it off. How would you accomplish this? – Jim Hunter Sep 24 '13 at 00:38
  • 1
    Do you know the total amount of phonenumbers before you iterate over them? Then I would do something like `var i:integer; x:array of OleVariant; begin SetLength(x,PhoneNumbers.Count); for i:=0 to PhoneNumbers.Count-1 do x[i]:=PhoneNumbers[i]; BSON(['Phones',x]);` – Stijn Sanders Sep 24 '13 at 06:50
  • Also, don't forget to accept the answer you find is the correct one. (The green checkmark on the left) – Stijn Sanders Sep 24 '13 at 06:51
  • A friend of mine just told me that I should be able to use BSON on my class without doing all the mental gymnastics I have posted here. You are the expert on this Stijn, how do I do that? I would MUCH rather just pass my class to a function in order to save it. What is the fastest way to get from class to database and back? I am going to head back to GITHub to see if I can find more information. Thanks for all your assistance on this. and you are going to get the Checkmark, don't worry about that. – Jim Hunter Sep 24 '13 at 21:13
  • You're talking about object persistence. In theory there's a thing called RTTI in Delphi that allows you to 'walk' over the properties of an object and build JSON or XML (or YAML or BSON or anything really) all by itself. I believe modern Delphi versions have built-in support for JSON, see this question: http://stackoverflow.com/questions/16709307/how-to-send-receive-json/16713142#16713142 – Stijn Sanders Sep 25 '13 at 08:20
  • Thing is I wanted the lightest possible connector for mongodb when I created TMongoWire, so I avoided using RTTI. But nothing is stopping you from using Delphi's 'toJSON' and using my from-JSON-to-BSON converter. Also I personally dislike 'automatic' object persistence since it forms a very big candidate for a problem-causer later on. Manually creating all the object migrations is a lot of work, but offers more chances to improve security and performance. About the security-issues this is a must-see: https://google-gruyere.appspot.com/ – Stijn Sanders Sep 25 '13 at 08:26
  • Thanks, after looking through the source code I came to the conclusion that this driver did not do object persistence. My friend is using the C# or C++ version of the driver and it did have object persistence. I am able to persist my objects by using the Delphi class TJSONMarshal. It turns the object to JSON and I can pass that JSON to your JSONToBSON to save it to the database. Knowing what I have to do to get this completed, I can see why it is not part of TMongoWire. There is no simple way to persist an object unless it is a simple object. Thanks for your assistance and the driver! – Jim Hunter Sep 25 '13 at 08:34
  • Stijn, quick question. Why is it that when I try and do something very similar to what you do in your demo I get a different result. On start of a page, I want to get all the company names and load them (eventually) into a combobox. This is the code I am playing with: – Jim Hunter Sep 27 '13 at 09:46
  • If you only need the company names, you should consider passing `BSON(['CompanyName',1])` as ReturnFieldSelector to Get (third parameter) – Stijn Sanders Sep 27 '13 at 23:15