I try to use the Fractal library from The PHP League in my project
I have model: Object with fields id, name. It has relation prototypes as one to one.
So, model Prototype has relation Fields. Where model Fields contains fields: name, id.
Also there is separated model: ObjectFields that contains values for each object fields. For example:
object_id | value
1 1
In result I need to get output JSON:
objects : {
"id" : 1,
"name" : "Weapon",
"prototype": {
"id" : 1,
"name" : "Prototype Name",
"fields" : {
"field_name" : ObjectFields.value
}
}
}
Look please on
"fields" : {
"field_name" : ObjectFields.value
}
so, It would be field name as key and value from model ObjectFields.
Now I do request using query as:
Object::with("prototype.field.name.value");
It returns me nested output object, but I need that last 3 realations will be in one object by key field.name
Related
Is there a way to only limit the number of columns that one can select in a nested eager loading in Laravel?
Currently, I have 3 models that inter-relate. For instance, let's assume that we have the Publisher model, Authors model, and books model.
A publisher has a relationship with the Authors and the Authors have a relation with the book's models.
The Publisher model has columns like:
id
name
address
fax number
email address
The author's models contain:
id
name
address
email
published books
publishers_id
The books models contain:
id
title
authors_id
published_on
category
If I want to check the books that have been published by a given publication company: This is how I pull the records
$published_books::Publisher::with('authors.books')->take(1);
With this, I get a response like this:
"id" : 1,
"name" : "Longhorn Ke",
"address" : "14th Street",
"fax number" : "null",
"email_address" : "longhorn#mail.com",
"author" :{
"id" : 4,
"name" : patel,
"email" : patelguru#mail.com,
"published_books" : 12,
"publishers_id" : 1,
"books" : {
"id": 1,
"title" : "Art of life",
"authors_id" : 1,
"published_on" : "2020-07-12 14:22:25",
"category" : "Life teachings",
}
}
What I want is that when I load a book through the relationship I only want to get the name of the publisher, name of the author and the books details as shown below:
"id" : 1,
"name" : "Longhorn Ke",
"author" :{
"id" : 4,
"name" : patel,
"books" : {
"id": 1,
"title" : "Art of life",
"authors_id" : 1,
"published_on" : "2020-07-12 14:22:25",
"category" : "Life teachings",
}
}
How can I achieve that using eloquent? At this point, I understand that eloquent allows selection of specific columns on a nester load as shown in this link https://laravel.com/docs/master/eloquent-relationships#eager-loading-specific-columns but how do I do it in all the models to achieve the code result show above
For the top-most model you need select(); for the relationships you need relationship:id,...:
$published_books = Publisher::with(['authors.books', 'authors:id,name'])
->select('id', 'name')
->take(1);
I have document like this:
{
"_id" : ObjectId("591ed2f0470e6ccc143c986e"),
"name" : "Planets",
"prototype_id" : null,
"parameters" : [
"591eefe3470e6cd70c3c9872",
"591eefc3470e6c500f3c9872",
"591eedbe470e6cd70c3c9871"
],
"available" : "1"
}
I tried to set [] for field parameters if value 591eefe3470e6cd70c3c9872 exists in this array.
I tried:
$new = array('$set' => array("parameters" => []));
$this->collection->update(array("parameters" => "591eedbe470e6cd70c3c9871"), $new);
It does not work...
MongoDB's update() and save() methods are used to update document into a collection. The update() method updates the values in the existing document while the save() method replaces the existing document with the document passed in save() method.
MongoDB Update() Method
The update() method updates the values in the existing document.
Syntax
The basic syntax of update() method is as follows −
db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA)
Consider the mycol collection has the following data
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"My Overview"}
Following example will set the new title 'New MongoDB Tutorial' of the documents whose title is 'MongoDB Overview'.
db.mycol.update({'title':'MongoDB Overview'},{$set:{'title':'New MongoDB Tutorial'}})
db.mycol.find()
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"New MongoDB Tutorial"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"My Overview"}
By default, MongoDB will update only a single document. To update multiple documents, you need to set a parameter 'multi' to true.
db.mycol.update({'title':'MongoDB Overview'},
{$set:{'title':'New MongoDB Tutorial'}},{multi:true})
I have two collections - users and chats. Each chat message has a structure like the following:
_id: ObjectId
from: ObjectId // user _id
to: ObjectId // user _id
message: String
date_created: Date
And each user has:
_id: ObjectId
name: String
username: String
// ... not important stuff
I need to fetch conversations that are only sent to me and the result should be in the following way:
{
data: [
{
"id": conversation_id,
"title": username,
"message": message_excerpt
},...
]
}
My problem is trying to get the username from the reference because I don't want to make 20 fetch queries to get 20 different usernames. I would have added the username when the conversation is first created but I can't because the username can be changed any time. This would create an inconsistency between the username and the conversation title. How should I handle this problem? This is the first time I wished there was a JOIN in Mongo.
Two possibilities:
1: Add the username to chat message documents. Like you said, if the username changes, you need to change the username on all the user's chats.
2: Do an application-level join. You don't need to do 20 queries to get the 20 names. You can first retrieve all the chats, then collect all of the user_id values and do one query. For example:
var results = [
{ "_id" : 0, "from" : 43, "to" : 86, "message" : "sup?" },
{ "_id" : 1, "from" : 99, "to" : 86, "message" : "yo" }
]
var from_users = db.users.find({ "_id" : { "$in" : results.map(function(doc) { return doc.from }) } }).toArray()
Now you can use the from_users to populate the username into results or create your desired document structure. Note that results from the $in are necessarily returned in the order of elements in the array argument to $in - this is commonly expected/desired but it's not the case.
I have a pretty big MongoDB document that holds all kinds of data. I need to identify the fields that are of type array in a collection so I can remove them from the displayed fields in the grid that I will populate.
My method now consists of retrieving all the field names in the collection with
This was taken from the response posted here MongoDB Get names of all keys in collection
mr = db.runCommand({
"mapreduce" : "Product",
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "things" + "_keys"
})
db[mr.result].distinct("_id")
And running for each of the fields a query like this one
db.Product.find( { $where : "Array.isArray(this.Orders)" } ).count()
If there's anything retrieved the field is considered an array.
I don't like that I need to run n+2 queries ( n being the number of different fields in my collection ) and I wouldn't like to hardcode the fields in the model. It would defeat the whole purpose of using MongoDB.
Is there a better method of doing this ?
I made a couple of slight modifications to the code you provided above:
mr = db.runCommand({
"mapreduce" : "Product",
"map" : function() {
for (var key in this) {
if (Array.isArray(this[key])) {
emit(key, 1);
} else {
emit(key, 0);
}
}
},
"reduce" : function(key, stuff) { return Array.sum(stuff); },
"out": "Product" + "_keys"
})
Now, the mapper will emit a 1 for keys that contain arrays, and a 0 for any that do not. The reducer will sum these up, so that when you check your end result:
db[mr.result].find()
You will see your field names with the number of documents in which they contain Array values (and a 0 for any that are never arrays).
So this should give you which fields contain Array types with just the map-reduce job.
--
Just to see it with some data:
db.Product.insert({"a":[1,2,3], "c":[1,2]})
db.Product.insert({"a":1, "b":2})
db.Product.insert({"a":1, "c":[2,3]})
(now run the "mr =" code above)
db[mr.result].find()
{ "_id" : "_id", "value" : 0 }
{ "_id" : "a", "value" : 1 }
{ "_id" : "b", "value" : 0 }
{ "_id" : "c", "value" : 2 }
In mongodb, We can assign our own value to _id field and the "_id" field value may be of any type, other than arrays, so long as it is a unique -- From the docs.
But in my live database, i can see some records were duplicated as follows,
db.memberrecords.find().limit(2).forEach(printjson)
{
"_id" : "999783",
"Memberid" : "999783",
"Name" : "ASHEESH SHARMA",
"Gender" : "M",
}
{
"_id" : "999783",
"Memberid" : "999783",
"Name" : "Sanwal Singh Meena",
"Gender" : "M",
}
In above records, the same _id value inserted twice in the table. When i tested with local database it is not allowing to insert the same _id record and throwing error as follows,
E11000 duplicate key error index: mongoms.memberrecords.$_id_ dup key: { : "999783" }
Below is the Indexes for my live memberrecords table(for your reference),
db.memberrecords.getIndexes()
[
{
"name" : "_id_",
"ns" : "mongoms.memberrecords",
"key" : {
"_id" : 1
},
"v" : 0
},
{
"_id" : ObjectId("4f0bcdf2b1513267f4ac227c"),
"ns" : "mongoms.memberrecords",
"key" : {
"Memberid" : 1
},
"name" : "Memberid_1",
"unique" : true,
"v" : 0
}
]
Note: i have two sharding for this table.
Any suggestion on this please,
Is your shard key the _id field? You can only have one unique index enforced across a cluster: the shard key (otherwise the server would have to check with every shard on every insert).
So: on a single a shard, _id will be unique. However, if it isn't your shard key, all bets are off across multiple shards.
See http://www.mongodb.org/display/DOCS/Sharding+Limits#ShardingLimits-UniqueIndexesDOCS%3AIndexes%23UniqueIndexes.