I am currently using "spring-boot-starter-data-mongodb" for persisting documents to a collection in mongodb.
The document contains a List with nested objects like:
{
foo:bar,
foos: [
{
foo1: bar1,
foo2: bar2
},
{
foo1: bar4,
foo2: bar3
}
]
}
The mapping of these documents consist the following:
private String foo;
private List<Foo> foos;
Foo:
private String foo1;
private String foo2;
The business logic is heavily depending on the order of the foos (the List elements).
The real questions are:
Are inserting a document preserves the order of the elements, so that the first item in the list will be the first in the JSON and so on?
Are querying preserves the order of the elements, so if an element is the N-th member of the document in the DB, will it be the N-th element in the mapped object as well?
Currently it seems to be true but I need to make sure it is guaranteed.
Yes, AFAIK the sort is guaranteed because MongoDB stores the document as it is. The document is stored and there is no reason to modify values from the array when read it.
Also, there are a couple questions here in StackOverflow like:
Do arrays stored in MongoDB keep their order?
Is the order of elements inside a MongoDB array guaranteed to be consistent?
Are arrays in MongoDB documents always kept in order?
So as seen before, assuming MongoDB preserves the order of elements within an array, when querying the collection in Spring Data MongoDB the returned documents will be mapped to the corresponding objects.
So the order of elements in the List of your object will be the same as the order of the elements in the array into MongoDB document.
Related
Firstly, the document schema am querying on, is as follows:
{x:10, y:"temp", z:20}
There are multiple other documents in the collection with the same schema as above.
Now, I have a list where each element contains, pair of values belonging to keys x and y. This can be pictured as:
[{10,"temp"}, {20,"temp1"}, .....]
keys -> x y x y
Now, am aware, that if I process the array in a loop and take each pair, I can construct a query like:
query.addCriteria(Criteria.where("x").is(10).and("y").is("temp"))
This will return the document if it matches the AND criteria. I can query with all the pairs in the list in such a manner. But this approach will involve a high number of calls to the data base since for each pair in the list, there is a database call.
To avoid this, Is there any way I can query for all the documents that match this AND criteria for each element in the list, in a single call, using spring data MongoDb Api? Framed differently, I want to avoid looping through the array and making multiple calls, if possible.
You could use Criteria.orOperator to return each Document that match at least one Criteria of your list.
Build your list of Criteria looping over your list
List<Criteria> criteriaList = new ArrayList<>();
for (item : yourList) {
criteriaList.add(Criteria.where("x").is(item.x).and("y").is(item.y));
}
Build your query using orOperator:
Query.query(new Criteria.orOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));
I had a collection with an embedMany attribute using strategy=set, so an ArrayCollection was stored. However we deleted some items from the array and now there are some documents with keys not sequential integers.
I need to solve this inconsistence, how can I do that?
You could use $type operator and query for all documents where your embedManyField is of type object. Once you have these documents, apply array_values to fields where array shall be stored and save them again. Also to avoid such situations in future you should change your collection's strategy to either setArray or atomicSetArray.
using document oriƫnted database mongodb and the Object Document Mapper (ODM) morphia
Lets say we have 3 different classes; Object, Category and Action.
These object are all stored in the collections; objects, categories and actions.
Category and Action are references of Object
#Entity("objects")
public class Object {
#Id
#Property("id")
private ObjectId id;
#Reference
private Category category;
private Action action;
...
}
#Entity("categories")
public class Category {
#Id
public String categoryTLA;
public String categoryName;
...
}
#Entity("actions")
public class Action implements BaseEntity {
#Id
public String action;
public int accesLevel;
...
}
The documents with the current implementation are stored like:
Mongo (Server/location)
store (database)
objects (collection)
object (document)
object
object
categories
categorie
categorie
categorie
actions
action
action
action
Is it possible to store 2 different Objects, in this case Category and Action, in one collection, like shown in the next example? Both with their own identification!
Mongo
store
objects
object
object
object
settings
categorie
categorie
categorie
action
action
action
Absolutely, it's possible to store multiple types of documents in a single collection. In fact, that's one of the strengths of a document oriented database like Mongo. However, you may not want to combine them without considering some issues (positive and negative):
You can't do cross-collection or document SQL-like JOINs. So, having documents in one or more collection won't change that behavior.
You can use aggregation only in a single collection, so you may be able to perform some aggregation style queries more conveniently if a collection has multiple document types rather than split across collections (both the aggregation framework and Map-Reduce operate only on a single collection at a time).
In order to deserialize a document into an object in Morphia, you'll need to know what type a given document represents. You may need to add a field to the document indicating the type, unless there are other ways that can safely represent the type of document so that the deserialization process works correctly. An Action can't be a Category for example. If you did the equivalent of FindAll and there were multiple document types, unless the deserializer can evaluate the document structure before deserialization starts, your code may not work as desired.
It's likely that you'll need to index various properties of your documents/Objects. If you index based on document types (say Action has an index that is unqiue from Category, all documents inserted into the collection containing both will run through the indexer, for all indexes defined in the collection. That can impact performance depending on the nature of the indexes. This means that all documents in the collection will be indexed regardless of whether the index makes sense. This is often a compelling reason to not combine multiple document types that do not share common indexing traits.
Unless you need to do specific types of queries that require all documents to be in a common collection, I'd likely leave them in separate collections, especially if you plan on using custom indexes for various document types/schemas.
yes. but probably you need to add field "documentType" to any document to distinguish documents
Lets assume that I have two collections in my Mongo database: A & B. Each A document may have reference to B, but B documents don't have references back to A.
How can I efficiently find all documents in B that are not referenced by a document in A?
Is there a more effective approach than retrieving all documents in B and manually comparing against A documents? Can this be done with map reduce?
Should I consider adding references from B to A to support the query? Since Mongo doesn't support transactions, I had avoided any two way references to avoid any chance of an inconsistent state in the event of a failure.
Also, I need to be able to effectively page through these results, if that impacts the solution.
In pseudo-code:
// Get the set of B document ids that are referenced by A documents.
var bref_ids = db.A.distinct('b_id');
// Get the set of all other B documents.
var unreferenced_b_docs = db.B.find({_id: {$nin: bref_ids}});
My question may be not very good formulated because I haven't worked with MongoDB yet, so I'd want to know one thing.
I have an object (record/document/anything else) in my database - in global scope.
And have a really huge array of other objects in this object.
So, what about speed of search in global scope vs search "inside" object? Is it possible to index all "inner" records?
Thanks beforehand.
So, like this
users: {
..
user_maria:
{
age: "18",
best_comments :
{
goodnight:"23rr",
sleeptired:"dsf3"
..
}
}
user_ben:
{
age: "18",
best_comments :
{
one:"23rr",
two:"dsf3"
..
}
}
So, how can I make it fast to find user_maria->best_comments->goodnight (index context of collections "best_comment") ?
First of all, your example schema is very questionable. If you want to embed comments (which is a big if), you'd want to store them in an array for appropriate indexing. Also, post your schema in JSON format so we don't have to parse the whole name/value thing :
db.users {
name:"maria",
age: 18,
best_comments: [
{
title: "goodnight",
comment: "23rr"
},
{
title: "sleeptired",
comment: "dsf3"
}
]
}
With that schema in mind you can put an index on name and best_comments.title for example like so :
db.users.ensureIndex({name:1, 'best_comments.title:1})
Then, when you want the query you mentioned, simply do
db.users.find({name:"maria", 'best_comments.title':"first"})
And the database will hit the index and will return this document very fast.
Now, all that said. Your schema is very questionable. You mention you want to query specific comments but that requires either comments being in a seperate collection or you filtering the comments array app-side. Additionally having huge, ever growing embedded arrays in documents can become a problem. Documents have a 16mb limit and if document increase in size all the time mongo will have to continuously move them on disk.
My advice :
Put comments in a seperate collection
Either do document per comment or make comment bucket documents (say,
100 comments per document)
Read up on Mongo/NoSQL schema design. You always query for root documents so if you end up needing a small part of a large embedded structure you need to reexamine your schema or you'll be pumping huge documents over the connection and require app-side filtering.
I'm not sure I understand your question but it sounds like you have one record with many attributes.
record = {'attr1':1, 'attr2':2, etc.}
You can create an index on any single attribute or any combination of attributes. Also, you can create any number of indices on a single collection (MongoDB collection == MySQL table), whether or not each record in the collection has the attributes being indexed on.
edit: I don't know what you mean by 'global scope' within MongoDB. To insert any data, you must define a database and collection to insert that data into.
Database 'Example':
Collection 'table1':
records: {a:1,b:1,c:1}
{a:1,b:2,d:1}
{a:1,c:1,d:1}
indices:
ensureIndex({a:ascending, d:ascending}) <- this will index on a, then by d; the fact that record 1 doesn't have an attribute 'd' doesn't matter, and this will increase query performance
edit 2:
Well first of all, in your table here, you are assigning multiple values to the attribute "name" and "value". MongoDB will ignore/overwrite the original instantiations of them, so only the final ones will be included in the collection.
I think you need to reconsider your schema here. You're trying to use it as a series of key value pairs, and it is not specifically suited for this (if you really want key value pairs, check out Redis).
Check out: http://www.jonathanhui.com/mongodb-query