Spring Data MongoDB - Embedded Document as Reference in Other Document - spring

I'd like to know if it's possible (or even correct) to use embedded documents as reference in other documents.
I know I can move the embedded document to its own collection but the main goal is to have the performance benefit of embedded document and also avoid duplication.
For example:
User
{
_id: ObjectId("4fed0591d17011868cf9c982"),
_class: "User"
...
addresses: [ {
_id: ObjectId("87KJbk87gjgjjygREewakj86"),
_class: "Address",
...
} ]
}
Order
{
_id: ObjectId("gdh60591d123487658cf9c982"),
_class: "Order",
...
address: ObjectId("87KJbk87gjgjjygREewakj86")
}

Your case reminds me of the typical relational approach, which I was a victim of, too, when starting to use document-oriented DBs. All of your
entities in the example are referenced, there is no redundancy anymore.
You should start to get used to the idea of letting go normalization and starting to duplicate data. In many cases it is hard to determine which data should be referenced and which should be embedded. Your case tends to be quite clear, though.
Without knowing your entire domain model, the address seems to be a perfect candidate for a value object. Do not maintain an Address collection, embed it within the user object. In Order, you could either make a reference to the user, which gives you implicitly the address object and might make sense, since an order is made by a user.
But...I recommend that you embed the address entirely in the Order. First, it is faster since you don't need to resolve a reference. Second, the address in shipped orders should never change! Consider orders of the last year. If you hold a reference to the address you would lose the information to which address they were shipped, once the user changes his address.
Suggestion: Always take a snapshot of the address and embed it in the Order. Save the MongoDB ID of the user as a regular string (no #DBRef) within the `Order. If a user should change his address, you can make a query for all non-shipped orders of that user and amend the address.

Since you asked if this is even correct, I would say, gently, "No." At least not typically.
But if you did want to insist on using an embedded address from user:
You can reference the user embedded address in the Order object, just not the way you might think! If you stored the id of the user in the order (it should already be there if Order belongs_to User), then you merely use user.address instead of copying the address instance as you have done.
ALTERNATIVE
I hope to illustrate a better approach to modeling the domain...
A more common approach is to instantiate a new order object, using the user's address as the default "ship to" address for the order, yet allow the user to override the shipping address if desired. In theory, each order could have a different "ship to" address.
Just because two classes have an address, does not mean they are necessarily the same address.
COMMENTARY
Orders are more of an historical document, versus one that changes. Therefore, Orders are generally immutable once placed, your model allows the address to change every time the user changes their address. That change ripples into the Orders, and would be incorrect insofar as normal order business logic goes.
Assume your address last year was in Spain and you had Order #1 show Spain when you ran a report of Orders last year. Imagine if your address this year is now Portugal and Order #1 now shows Portugal in the same report. That would be factually incorrect.
BTW: #Matt gave you the tip that from a "problem domain" perspective, you likely do not want to model it as you have. I am merely elaborating on that...

Since I got no answer I will post here how I did it. If you have a better solution I am happy to here it.
It looks like there's no way to create/reference a collection inside another collection, so I had to extract the addresses from the user collection to it's own collection and create a reference in the User and Order collections as mentioned here. I was expecting something more flexible, but couldn't find one.
User
{
_id: ObjectId("4fed0591d17011868cf9c982"),
_class: "User"
...
addresses: [ {
"$ref" : "addresses",
"$id" : ObjectId("87KJbk87gjgjjygREewakj86")
} ]
}
Address
{
_id: ObjectId("87KJbk87gjgjjygREewakj86"),
...
}
Order
{
_id: ObjectId("gdh60591d123487658cf9c9867"),
_class: "Order",
...
address: {
"$ref" : "addresses",
"$id" : ObjectId("87KJbk87gjgjjygREewakj86")
}
}

Related

Allow multiple provider states with parameters ( Golang )

As our team ( namely myself and two other developers ) spiked on PACT past week or so, one of the areas of concern is not having the ability associate parameters to provider states. The absence of this key feature ( which is slated for version 3 release ), we likely will not get buy in from each of our respective service sub-teams.
#MattFellows - Any projections on when version 3 might be available for Go? Any chance we can get this feature earlier?
Allow multiple provider states with parameters
In previous versions, provider states are defined as a descriptive string. There is no way to infer the data required for the state without encoding the values into the description.
{
"providerState": "an alligator with the given name Mary exists and the user Fred is logged in"
}
The change would be:
{
"providerStates": [
{
"name": "an alligator with the given name exists",
"params": {"name" : "Mary"}
}, {
"name": "the user is logged in",
"params" : { "username" : "Fred"}
}
]
}
You are correct in that it won't be available until version 3.
You can still achieve what you are after, however. The state itself is just a handle for the Consumer to some set of data on the Provider - that can be a one-to-one or one-to-many mapping - it's completely up to you.
Typically the Provider is notified of the state during verification, it will then setup a test data fixture (often seeding a database) that sets up the 'state' of the entire system based on that reference, which allows the Consumer test to run.
Whilst the ability to pass through parameters and multiple states is nice, it's somewhat an advanced feature and I very much doubt this will be the first problem you run into as a team. I've never needed to use them myself.
For a crude but effective example of this, take a look at the gin code in the examples folder of the project.

In Local Datastore chapter, fromPin and fromlocaldatastore

Just like as title, I want to ask what difference between
fromPin()
and
fromLocalDatastore()
By the way, Pin and datastore two terminologies. What difference between two of them ?
Thanks.
There is a slight difference and you can see it from the docs and from the decompiled code of the Parse library (okay, this last one is more complicated...).
The docs says:
fromLocalDatastore(): Change the source of this query to all pinned objects.
fromPin(): Change the source of this query to the default group of pinned objects.
Here you can see that, interally on Parse, there is a way to get all the objects from the entire set of pinned data, without filters, but also from a so-called "default group". This group is defined in the Parse code with the following string: _default (o'rly?).
When you pin something using pinInBackground, you can do it in different ways:
pinInBackground() [without arguments]: Stores the object and every object it points to in the local datastore.
This is what the docs say, but if you look at the code you'll discover that the pin will be actually performed to the... _default group!
public Task<Void> pinInBackground() {
return pinAllInBackground("_default", Arrays.asList(new ParseObject[] { this }));
}
On the other hand, you can always call pinInBackground(String group) to specify a precise group.
Conclusion: every time you pin an object, it's guaranteed to be pinned to a certain group. The group is "_default" if you don't specify anything in the parameters. If you pin an object to your custom group "G", then a query using fromPin() will not find it! Because you didn't put it on "_default", but "G".
Instead, using fromLocalDatastore(), the query is guaranteed to find your object because it will search into "_default", "G" and so on.

How to best create sorted sets with Redis

I'm still a bit lost when it comes to Sorted Sets and how to best construct them. Currently I have a simple set of activity on my site. Normally it will display things like User Followed, User liked, User Post etc. The JSON looks something like...
id: 2808697,
activity_type: "created_follower",
description: "Bob followed this profile",
body: null,
user: "Bob",
user_id: 99384,
user_profile_id: 233007,
user_channel_id: 2165811,
user_cube_url: "bob-anerson",
user_action: "followed this profile",
buddy: "http://s3.amazonaws.com/stuff/ju-logo.jpg",
affected: "Bill Anerson is following Jon Denver.",
created_at: "2014-06-24T20:34:11-05:00",
created_ms: 1403660051902,
profile_id: 232811,
channel_id: 2165604,
cube_url: "jondenver",
type: "profiles",
So if the activity type can be multiple things (IE Created Follow, Liked Event, Posted News, ETC) how would I go about putting this all in a sorted set? I'm already sure I want the score to be the created_ms but the question is, can I do multiple values in a sorted set that all have keys as fields? Should most of this be in a hash? I realize this is a fairly open question but after trying to wrap my head around all the tutorials Im just concerned about setting up the data structure before had so I dont get caught to deep in the weeds.
A sorted set is useful if you want to... keep stuff sorted! ;)
So, I assume you're interested in keeping the activities sorted by their creation time (ms). As for storing the actual data, you have two options:
Use the sorted set itself to store the data, even in native JSON format. Note that with this approach you'll only be able to fetch the entire JSON and you'll have to parse it at the client.
Alternatively, use the sorted to store "pointers" to hashes - i.e. the values will be key names in which you'll store the data. From your description, this appears the preferable approach.

Creating a unique ID in a form

I have a form that I have users fill out and then it gets e-mailed to me.
I am trying to get an example of how I would create an ID (based on my own conventions) that I can use to keep track of responses (and send back to the user so they can reference it later).
This is the convention I am striving for:
[YEAR]-[SERVICE CODE]-[DATE(MMDD)]-[TIME]
For example: "2012-ABC-0204-1344". I figured to add the TIME convention in the instance that two different users pick the same service on the same date rather than try to figure out how to only apply it IF two users picked the same service on the same date.
So, the scenario is that after the user goes through my wizards inputting their information and then click "Submit" that this unique ID would be created and attached to the model. Maybe something like #Model.UniqueID so that in an e-mail response I send to the user it shows up and says "Reference this ID for any future communication".
Thanks for any advice/help/examples.
In your post action
[HttpPost]
public ActionResult Create(YourModel model)
{
model.UniqueId = GenerateUniqueId(serviceCode);
}
public string GenerateUniqueId(string serviceCode)
{
return string.Format("{0}-{1}-{2}", DateTime.Now.Year, serviceCode, Guid.NewGuid().ToString().Replace("-",""); //remove dashes so its fits into your convention
}
but this seems as I'm missing part of your question. If you really want unique, use a Guid. This is what we've used in the past to give to customers - a guid or a portion of one. IF you use a portion of one ensure you have logic to handle a duplicate key. You don't need to worry about this though if using a full guid. If the idea is just to give to a customer then ignore the rest of the data and just use a guid, since it can easily be looked up in the database.

Magento View 'Company Name' Instead Of First/Last Name

Can Magento view/manage our customers by their business name in addition to their contact names to find them easily? It is being used for B2B, so when emails go out they are pulling the customer’s name, instead of the company name which is more appropriate.
Is this a global setting?
thanks in advance.
Magento stores business name on the customer's address by default, so it's a little harder to get to.
There's no reason you cannot add another customer field to put the company name on the customer record itself. That way you'll have no problem accessing it, and can change other screens in the system to reflect it.
If you don't want to go to those lengths, you could always implement a method that pulls the company name from the default address, and save it into the session by default, for easier retrieval.
EDIT: Better idea.
Looking through the sales email templates, there are two methods that are used to grab a customer's name:
$order->getCustomerName();
$order->getBillingAddress()->getName();
I don't see any separate references to the company name, so you should be able to substitute these two methods for your own and get the desired outcome. You'll need to create your own module and override the models for customer/address and sales/order (others have covered this in depth elsewhere). Then create methods that look something like this:
public function getCustomerName() {
if($this->getBillingAddress()->getCompany()) {
return $this->getBillingAddress()->getCompany();
}
return parent::getCustomerName();
}
That's the example for sales order, modify accordingly for customer. Now your company names will be used whenever available, and when they aren't the fallback will be to the original implementation (customer name).
Hope that helps!
Thanks,
Joe
You are correct about the universal application. If you did want just the emails, the concern is whether you have access to your custom function where you need it. If there's no object handy, I'm not positive that you will be able to call just any method that you need to.
An approach that would work in this case would be to override the two objects mentioned below, but to instead add a getCompanyName method to them. That way, you'll have the right objects to call, and you can edit the emails specifically to taste.

Resources