Difference between and / or clause in mongo db - mongodb

I am new to mongo db and trying to understand how to query a db.
I was reading a tutorial from this link http://code.tutsplus.com/tutorials/getting-started-with-mongodb-part-1--net-22879
Following this tutorial I created a simple db like below,
db.nettuts.insert({
first: 'matthew',
last: 'setter',
dob: '21/04/1978',
gender: 'm',
hair_colour: 'brown',
occupation: 'developer',
nationality: 'australian'
});
db.nettuts.insert({
first: 'james',
last: 'caan',
dob: '26/03/1940',
gender: 'm',
hair_colour: 'brown',
occupation: 'actor',
nationality: 'american'
});
db.nettuts.insert({
first: 'arnold',
last: 'schwarzenegger',
dob: '03/06/1925',
gender: 'm',
hair_colour: 'brown',
occupation: 'actor',
nationality: 'american'
});
db.nettuts.insert({
first: 'tony',
last: 'curtis',
dob: '21/04/1978',
gender: 'm',
hair_colour: 'brown',
occupation: 'developer',
nationality: 'american'
});
db.nettuts.insert({
first: 'jamie lee',
last: 'curtis',
dob: '22/11/1958',
gender: 'f',
hair_colour: 'brown',
occupation: 'actor',
nationality: 'american'
});
db.nettuts.insert({
first: 'michael',
last: 'caine',
dob: '14/03/1933',
gender: 'm',
hair_colour: 'brown',
occupation: 'actor',
nationality: 'english'
});
db.nettuts.insert({
first: 'judi',
last: 'dench',
dob: '09/12/1934',
gender: 'f',
hair_colour: 'white',
occupation: 'actress',
nationality: 'english'
});
and was trying to use querys like this below
db.nettuts.find({gender: 'm'});
which returned all the actors who are male.
When I tried the command
db.nettuts.find({gender: 'm', $or: [{nationality: 'english'}]});
it returned.
> db.nettuts.find({gender: "m", $or: [{nationality: "english"}]});
{ "_id" : ObjectId("53064b7979d90b140e53df3e"), "first" : "michael", "last" : "caine", "dob" : "14/03/1933", "gender" : "m", "hair_colour" : "brown", "occupation" : "actor", "nationality" : "english" }
>
When I tried the same command, this time with "and" clause
db.nettuts.find({gender: 'm', $and: [{nationality: 'english'}]});
I got the same output as when I used $or
> db.nettuts.find({gender: "m", $and: [{nationality: "english"}]});
{ "_id" : ObjectId("53064b7979d90b140e53df3e"), "first" : "michael", "last" : "caine", "dob" : "14/03/1933", "gender" : "m", "hair_colour" : "brown", "occupation" : "actor", "nationality" : "english" }
>
So given these two output what is the difference between "or" clause and "and" clause here. Please help me understand.

Using $or or $and with an array with only one entry is quite pointless, because both operators apply to the array which is assigned to them. They don't apply to any other parts of the match-object.
When you want to find all actors which are male or english, you would do this:
db.nettus.find({
$or: [
{ "gender": "m"},
{ "nationality": "english"}
]
});
To find all actors which are male and english, you don't even need the $and-operator:
db.nettus.find({
"gender": "m",
"nationality": "english"
});
There are quite few situations where you really must use the $and-operator. The only situation where you have no alternative is when you need to apply the same operator to the same field multiple times. In this example we select all people whose age can be divided by 3 and 5.
db.people.find({
$and: [
{ age: $mod [ 3, 0] },
{ age: $mod [ 5, 0] }
]
});

Related

How to update a property of object in a nested array in MongoDB?

I am trying to update a property from nested array object. I use this code but not working.
This is my data
[
{
_id: ObjectId("630a869a887d39ef359ef6e6"),
firstName: 'Esra',
lastname: 'Demirci',
age: 33
},
{
_id: ObjectId("630a86a5887d39ef359ef6e7"),
firstName: 'Efe',
lastname: 'Demirci',
age: 7,
history: [ { disease: 'flue', threatment: 'given serum' } ]
},
{
_id: ObjectId("630a8e10887d39ef359ef6e8"),
firstName: 'Ali',
lastname: 'Demirci',
age: 34,
history: [
{ disease: 'cold', threatment: 'medicine given' },
{ disease: 'alergy', threatment: 'refered alergy department' }
]
}
]
This is my query in mongodb
db.patientData.update({"history.disease":"cold"},{$set:{"history.disease":"ali updated this one"}})
I wanna update data which has disease:"cold" value to new value.
Try using the $ sign when updating in MongoDB, like so:
db.patientData.update({"history.disease":"cold"},{$set:{"history.$.disease":"ali updated this one"}})

MongoDB add weights to index based on search order

Let's say I have a schema with an index of:
Person.index({ name: 'text', occupation: 'text', country: 'text' })
and a collection of Person documents such as:
[
{
name: 'John Doe',
occupation: 'Doctor',
country: 'Canada'
},
{
name: 'Mary Smith',
occupation: 'Doctor',
country: 'Brazil'
}
]
When I query with a search term like the following:
PersonModel.find(
{ $text: { $search: 'Mary Doctor Canada' } },
{ score: { $meta: 'textScore' } }
).sort(
{ score: { $meta: 'textScore' } }
)
How can I ensure that the first word in the search term has a higher importance than that of the following? In this instance, how can I make it that "Mary" is received a higher text score than "Canada" in the search term?
Similarly, if the search term was instead "Brazil John", then how can I make sure that Mary receives the higher text score, since the term "Brazil" comes before "John"?

MongoDB: Best way query users by given names and username

I'm trying to implement a user search that looks into the user's given names and their username, while also being able to sort results by relevance.
I tried creating a text index like this
db.users.createIndex({
username: 'text',
firstName: 'text',
lastName: 'text'
},
{
name: 'text_search',
default_language: 'en',
language_override: 'language'
})
But this doesn't take into account partial terms, so if I search for "Juan F", I get the following results
{ score: 3.7, username: "juanjo", firstName: "Juan", lastName: "Rivas F" },
{ score: 2.95, username: "Juan.rodriguez", firstName: "Juan", lastName: "Rodriguez" },
{...} // 6 more
{ score: 2.2, lastName: "Fuentes", firstName: "Juan", username: "juanfuentes" }
I understand that text indexes take into account similar words, but not partial terms, so with "Juan Fuente" I get the desired result, with "Juan F", "Juan Fu", etc, I don't.
Is there a way to improve this, in order to be able to implement a search that returns results as the user types into a search box?
Edit This is the query I tried:
db.users.find(
{ $text: { $search: "juan f" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

Laravel Eloquent using 'with' and 'where'

Using Laravel 5.4
I am reaching out as I am having a difficult time wrapping my head around this and after searching all day on the internet (and stackoverflow) I have not found a good solution to my problem that works.
Basically, I have a user object, that queries a child object which in turn includes a child object and I need to filter with where on that grandchild object.
It looks like this:
User =>
Pet(1) =>
PetServiceItem <= ServiceItem(1)
PetServiceItem <= ServiceItem(2)
PetServiceItem <= ServiceItem(3)
Pet(2) =>
PetServiceItem <= ServiceItem(1)
PetServiceItem <= ServiceItem(4)
PetServiceItem <= ServiceItem(5)
I'll post the relevant parts of the information so someone can tell me how this might be done.
User Model
class User extends Authenticatable
{
public function pets()
{
return $this->hasMany(Pet::class);
}
}
Pet Model
class Pet extends Model
{
protected $fillable = [
'id',
'user_id',
...];
public function user()
{
return $this->belongsTo(User::class);
}
public function petServiceItems(){
return $this->hasMany(PetServiceItem::class);
}
}
PetServiceItem model
class PetServiceItem extends Model
{
protected $fillable = [
'pet_id',
'service_item_id',
'approved'
];
protected $table = 'pet_service_item';
public function pet()
{
return $this->belongsTo(Pet::class);
}
public function serviceItem()
{
return $this->belongsTo(ServiceItem::class);
}
}
ServiceItem model
class ServiceItem extends Model
{
protected $fillable = [
'id',
...,
'start_date',
'end_date',
'...',
];
public function pets(){
return $this->hasMany(PetServiceItem::class);
}
}
Using Tinker I can do the following:
$user->pets()->with(['petServiceItems', 'petServiceItems.service'])->get()
And get this data:
=> Illuminate\Database\Eloquent\Collection {#1118
all: [
App\Pet {#1120
id: 1,
user_id: 6,
name: "Coco",
slug: "carol!coco",
image: "/dist/images/pets/carol/coco.jpg",
breed: null,
color: null,
gender: "Female",
birthdate: "2013-07-06 03:58:46",
fixed: 0,
weight: "48",
licensed: "",
tattoo: "",
microchip: "",
created_at: "2017-07-17 17:37:54",
updated_at: "2017-07-17 17:37:54",
petServiceItems: Illuminate\Database\Eloquent\Collection {#1126
all: [
App\PetServiceItem {#1132
id: 1,
provider_id: 2,
pet_id: 1,
service_item_id: 1,
approved: 1,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
serviceItem: App\ServiceItem {#1137
id: 1,
provider_id: 2,
type: "WALK",
subtype: "",
title: "7am 30min Walk between 7am and 10am",
desc: "Daily weekday walks between 7am and 10am",
day1: 0,
day2: 1,
day3: 1,
day4: 1,
day5: 1,
day6: 1,
day7: 0,
needs_approval: 0,
start_date: "2017-07-17 00:00:00",
end_date: "2017-10-17 00:00:00",
all_day: 0,
start_time: "07:00:00",
end_time: "10:00:00",
duration: 30,
pricing_one: 2000,
pricing_twoplus: 1800,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
deleted_at: null,
},
},
App\PetServiceItem {#1134
id: 3,
provider_id: 2,
pet_id: 1,
service_item_id: 4,
approved: 0,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
serviceItem: App\ServiceItem {#1139
id: 4,
provider_id: 2,
type: "AGILITY",
subtype: "",
title: "10am Agility Tu/Th",
desc: "Agility class # 10am Tuesdays and Thursdays for 90 minutes",
day1: 0,
day2: 0,
day3: 1,
day4: 0,
day5: 1,
day6: 0,
day7: 0,
needs_approval: 1,
start_date: "2017-07-17 00:00:00",
end_date: "2017-09-17 00:00:00",
all_day: 0,
start_time: "10:00:00",
end_time: "11:30:00",
duration: 90,
pricing_one: 5000,
pricing_twoplus: 4500,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
deleted_at: null,
},
},
],
},
},
App\Pet {#1123
id: 2,
user_id: 6,
name: "Ruby",
slug: "carol!ruby",
image: "/dist/images/pets/carol/ruby.jpg",
breed: null,
color: null,
gender: "Female",
birthdate: "2012-06-16 22:47:43",
fixed: 1,
weight: "53",
licensed: "",
tattoo: "",
microchip: "",
created_at: "2017-07-17 17:37:54",
updated_at: "2017-07-17 17:37:54",
petServiceItems: Illuminate\Database\Eloquent\Collection {#1119
all: [
App\PetServiceItem {#1133
id: 2,
provider_id: 2,
pet_id: 2,
service_item_id: 1,
approved: 1,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
serviceItem: App\ServiceItem {#1137},
},
App\PetServiceItem {#1135
id: 4,
provider_id: 2,
pet_id: 2,
service_item_id: 4,
approved: 0,
created_at: "2017-07-17 17:37:57",
updated_at: "2017-07-17 17:37:57",
serviceItem: App\ServiceItem {#1139},
},
],
},
},
],
}
Now I need to do a where clause on the ServiceItem for the start_date.
I tried:
$user->pets()->with(['petServiceItems', 'petServiceItems.serviceItem'])->where('service_items.start_date', '>=', '2017-01-01')->get()
But, I get this error:
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'service_items.start_date' in
'where clause' (SQL: select * from pets where pets.user_id = 6
and pets.user_id is not null and service_items.start_date >=
2017-01-01)'
How can I use the where clause (or something else if needed) to filter the data I need?
edited:
I have figured out that this is the SQL that I want (or close enough approximation):
select * from users
join (select * from pets) pet on users.id = pet.user_id
join (select * from pet_service_item) psi on psi.pet_id = pet.id
join (select * from service_items) si on si.id = psi.service_item_id
join (select * from providers) prov on prov.id = si.provider_id
where si.start_date >= '2017-07-17'
AND si.end_date <= '2017-10-18'
AND prov.id = 2
AND users.id = 6
Where clause use the name of the table and not the model. Try this:
$user->pets()->with(['petServiceItems', 'petServiceItems.serviceItem'])
->where('service_items.start_date', '>=', '2017-01-01')->get();
So, I'm posting this as I never really did get an answer and I ended up with a solution, but not exactly the one I was looking for.
If anyone is interested, in the end, this is how I did it (note: this flattened the data, which for all intents and purposes, worked fine in my scenario).
$services = App\ServiceItem::where('provider_id', '=', $provider->id)
->where('user.user_id', '=', $user->id)
->where('start_date', '<=', $end_date)
->where('end_date', '>=', $start_date)
->orWhereNull('end_date')
->where('pet.pet_user_id', '=', $user->id)
->whereNull('service_items.deleted_at')
->whereNUll('pet.pet_deleted_at')
->join(DB::raw('(select pet_id as psi_pet_id, service_item_id as psi_service_item_id from pet_service_items) psi'), function($join) {
$join->on('psi.psi_service_item_id', '=', 'service_items.id');
})
->join(DB::raw('(select id as pet_id, user_id as pet_user_id, name as pet_name, deleted_at as pet_deleted_at from pets) pet'), function($join) {
$join->on('pet.pet_id', '=', 'psi.psi_pet_id');
})
->join(DB::raw('(select id as user_id, name as user_name, deleted_at as user_deleted_at from users) user'), function($join) {
$join->on('user.user_id', '=', 'pet.pet_user_id');
});
return ['status' => 200, 'services' => $services->get()];

NoSQL: insert an array

I have a question in the homework assignment.
Suppose that each actor can work in multiple movies. We want to record the names of movies for each actor as an embedded array within a document of each actor.
Modify the following insertion query to add the following movies as an array: Life of Pie, Madagascar, and Hunger Games.
db.actor.insert({
first: 'matthew',
last: 'setter',
dob: '21/04/1978',
gender: 'm',
hair_colour: 'brown',
occupation: 'developer',
nationality: 'australian',
height_cm: 185
});
I thought it would be as easy as just adding this line into the code:
movies: ["Life of Pie", "Madagascar", "Hunger Games"]
but obviously, it's not that simple. I tried to find the syntax and examples for inserting an array, but had no luck.
According to the mongodb documentation, you had the right idea:
http://docs.mongodb.org/manual/core/document/
The example they give is:
var mydoc = {
_id: ObjectId("5099803df3f4948bd2f98391"),
name: { first: "Alan", last: "Turing" },
birth: new Date('Jun 23, 1912'),
death: new Date('Jun 07, 1954'),
contribs: [ "Turing machine", "Turing test", "Turingery" ],
views : NumberLong(1250000)
}
So, it's possible you were just missing a comma after height_cm: 185:
db.actor.insert({
first: 'matthew',
last: 'setter',
dob: '21/04/1978',
gender: 'm',
hair_colour: 'brown',
occupation: 'developer',
nationality: 'australian',
height_cm: 185,
movies: ["Life of Pie", "Madagascar", "Hunger Games"]
});