Put multiple fields in one index - mongodb

When I have a collection of users, with a structure like this:
{
...
phone:"XXXXXXXXXX",
email:"XXXXXXXXXX",
...
}
Is there a way to put both the fields phone and email into one index, for example called contactinfos, so that I can query my user by their phonenumber OR by their email address like this:
db.users.find({contactinfos:"E-Mail-Address or Phonenumber"})
?

You don't need to create an aggregate field. You can query your collection with $or operator:
db.users.find( { $or: [ { email: "email#somethingc.com"}, { phone: "123456" } ] } );
This will find all documents with either e-mail OR phone.
You can then create a compound index on both fields to make the query faster (if you're using MongoDB 2.4).
If you're using MongoDB 2.6 you can take advantage of index intersection and create two separate indexes for those fields.

Related

How to trim a value by a particular length and then apply lookUp in mongoDB

The main issue i'm facing is doing multi document joins. For example, when I try and run a query on orders by customer I can't find an easy way to join orders to customers on a customer id because in the orders object the customer id has _user$ appended to the beginning of the user ID and I don't know how to truncate that in an aggregation pipeline.
eg; In the order object, the customer is defined as _p_customer:"_User$8qXjk40eOd"
But in the user table the _id is just 8qXjk40eOd and therfore the default lookup function in charts cannot match the two.
Note: I'm using parse server and it stores pointers in the above mentioned way.
This is how the data is being stored in the mongoDB order collection.
customer field in the above image is the pointer to the _User collection
This is how the data is stored in the mongoDB _User collection.
My requirement is to write mongo query that find all users and their related orders count. I'm not able to do that because I don't how to remove _User$ from the order row and join it the _User via _id.
before lookup in aggregate substr the field you want to use in $lookup
db.collection.aggregate([
{
$addFields :{
nUser : { $substr: [ "$_p_customer", 6, -1 ] } // _User$ has 6 characters
}
},
{
$lookup :{
from:"usersCollection",
localField:"nUser",
foreignField : "_id",
as : "UserObject"
}
}
])

MongoDB: using indexes on multiple fields or an array

I'm new with mongo
Entity:
{
"sender": {
"id": <unique key inside type>,
"type": <enum value>,
},
"recipient": {
"id": <unique key inside type>,
"type": <enum value>,
},
...
}
I need to create effective seach by query "find entities where sender or recipient equal to user from collection" with paging
foreach member in memberIHaveAccessTo:
condition ||= member == recipient || member == sender
I have read some about mongo indexes. Probably my problem can be solve by storing addional field "members" which will be array contains sender and recipient and then create index on this array
Is it possible to build such an index with monga?
Is mongo good choise to create indexes like?
Some thoughts about the issues raised in the question about querying and the application of indexes on the queried fields.
(i) The $or and two indexes:
I need to create effective search by query "find entities where sender
or recipient equal to user from collection...
Your query is going to be like this:
db.test.find( { $or: [ { "sender.id": "someid" }, { "recipient.id": "someid" } ] } )
With indexes defined on "sender.id" and "recipient.id", two individual indexes, the query with the $or operator will use both the indexes.
From the docs ($or Clauses and Indexes):
When evaluating the clauses in the $or expression, MongoDB either
performs a collection scan or, if all the clauses are supported by
indexes, MongoDB performs index scans.
Running the query with an explain() and examining the query plan shows that indexes are used for both the conditions.
(ii) Index on members array:
Probably my problem can be solve by storing addtional field "members"
which will be array contains sender and recipient and then create
index on this array...
With the members array field, the query will be like this:
db.test.find( { members_array: "someid" } )
When an index is defined on members_array field, the query will use the index; the generated query plan shows the index usage. Note that an index defined on an array field is referred as Multikey Index.

how to populate field of one collection with count query results of another collection?

Kind of a complex one here and i'm pretty new to Mongo, so hopefully someone can help. I have a db of users. Each user has a state/province listed. I'm trying to create another collection of the total users in each state/province. Because users sign up pretty regularly, this will be an growing total i'm trying to generate and display on a map.
I'm able to query the database to find total number of users in a specific state, but i want to do this for all users and come out with a list of totals in all states/provinces and have a separate collection in the DB with all states/provinces listed and the field TOTAL to be dynamically populated with the count query of the other collection. But i'm not sure how to have a query be the result of a field in another collection.
used this to get users totals:
db.users.aggregate([
{"$group" : {_id:"$state", count:{$sum:1}}}
])
My main question is how to make the results of a query the value of a field in each corresponding record in another collection. Or if that's even possible.
Thanks for any help or guidance.
Looks like that On-Demand Materialized Views (just added on version 4.2 of MongoDB) should solve your problem!
You can create an On-Demand Materialized View using the $merge operator.
A possible definition of the Materialized View could be:
updateUsersLocationTotal = function() {
db.users.aggregate( [
{ $match: { <if you need to perform a match, like $state, otherwise remove it> } },
{ $group: { _id:"$state", users_quantity: { $sum: 1} } },
{ $merge: { into: "users_total", whenMatched: "replace" } }
] );
};
And then you perform updates just by calling updateUsersLocationTotal()
After that you can query the view just like a normal collection, using db.users_total.find() or db.users_total.aggregate().

MongoDB best optimisation on embedded documents using index

In MondoDB, how can you optimize better a collection with embedded documents using index, if you need to query the embedded document?
For example, in a collection with the following format:
{
name: “Andy”,
address: {
city: “London”,
street: “Sunny St.”
}
}
If we need to query by:
db.collection.find( {$and: [ {"address.city ": “London”}, {"address”: “Sunny St."} ] } )
Which type of index will be better:
1. db.collection.createIndex({"address":1})
2. db.collection.createIndex({"address.city ":1})
db.collection.createIndex({"address.street":1})
3. db.collection.createIndex({"address.city ":1, "address.street":1})
Thanks
for given query proposal number 3
db.collection.createIndex({"address.city ":1, "address.street":1})
will do the job as there is logical relation city=> street
if you need to get more precise output how mongo uses index and perform your own test use query.explain("executionStats") to see index usage.
more here

How can I query for a subdocument full of objects in Mongo?

So I have a document with an unknown number of objects in it, each with 2 properties. It's a collection of friend lists, and I'm trying to confirm if someone has a friend with a certain username before I allow a user to send a request. I'm keeping the list of friends in a subdocument, like this:
>>all the _id and other properties<<, "ownerFriends":[{"friendId":"an id goes here", "friendUsername": "username"}, {"friendId":"another id", "friendUsername":"username2"}]
I'm trying to do a query that will return username2 if given that as input, but I don't know how to do that with dot notation because I think you need to know the specific property to look for, and these are heterodox amounts of friend objects in the ownerFriends property.
If you want to select the ownerFriend object that has username as the friendUserName you can use the following selector (assuming your collection is called Friends):
Friends.find({
"ownerFriends.friendUsername": "username2"
}, {
fields: { "ownerFriends.$": 1}
});
You can find a detailed explanation of how to query an array of objects based on a property here:
http://www.curtismlarson.com/blog/2015/08/08/meteor-mongodb-array-property-selector/
In summary you have an object that contains keys, one of whose values is an array of objects. You can perform queries on the arrays using $elemMatch In your case:
MyCollection.find({ ownerFriends: { $elemMatch: { friendUsername: searchString }}});
Although I think you'll need to also query on the current user's _id. Not knowing the details of your collection, I can only speculate with:
MyCollection.find({ userId: Meteor.userId(), ownerFriends: { $elemMatch: { friendUsername: searchString }}});