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"}})
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"?
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" } })
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()];
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"]
});