Asked  7 Months ago    Answers:  5   Viewed   56 times

Can anyone assist in pointing me to a tutorial, library, etc. that will allow me to work with MongoDB from CodeIgniter?

 Answers

48

I'm not sure if its the "CodeIgniter way" but I created a CodeIgniter library that extends the Mongo class with an extra property to store the current database connection.

Here are the relevant code files from my project.

config/mongo.php

$config['mongo_server'] = null;
$config['mongo_dbname'] = 'mydb';

libraries/Mongo.php

class CI_Mongo extends Mongo
{
    var $db;

    function CI_Mongo()
    {   
        // Fetch CodeIgniter instance
        $ci = get_instance();
        // Load Mongo configuration file
        $ci->load->config('mongo');

        // Fetch Mongo server and database configuration
        $server = $ci->config->item('mongo_server');
        $dbname = $ci->config->item('mongo_dbname');

        // Initialise Mongo
        if ($server)
        {
            parent::__construct($server);
        }
        else
        {
            parent::__construct();
        }
        $this->db = $this->$dbname;
    }
}

And a sample controller

controllers/posts.php

class Posts extends Controller
{
    function Posts()
    {
        parent::Controller();
    }

    function index()
    {
        $posts = $this->mongo->db->posts->find();

        foreach ($posts as $id => $post)
        {
            var_dump($id);
            var_dump($post);
        }
    }

    function create()
    {
        $post = array('title' => 'Test post');
        $this->mongo->db->posts->insert($post);
        var_dump($post);
    }
}
Wednesday, March 31, 2021
 
rblarsen
answered 7 Months ago
78

You can't use a single aggregate() to do two grouped counts with your desired result format. Once the data has been grouped the first time you no longer have the details needed to create the second count.

The straightforward approach is to do two queries, as you are already doing ;-).

Thoughts on alternatives

If you really wanted to get the information in one aggregation query you could group on both fields and then do some manipulation in your application code. With two fields in the group _id, results are going to be every combination of group_name and status.

Example using the mongo shell :

db.users.aggregate(
    { $group: {
         _id: { group_name: "$group_name", status: "$status" },
         'total_sum': { $sum: 1 }
    }}
)

That doesn't seem particularly efficient and lends itself to some convoluted application code because you have to iterate the results twice to get the expected groupings.

If you only wanted the unique names for each group instead of the names + counts, you could use $addToSet in a single group.

The other obvious alternative would be to do the grouping in your application code. Do a single find() projecting only the group_name and status fields, and build up your count arrays as you iterate the results.

Saturday, May 29, 2021
 
felipsmartins
answered 5 Months ago
26

To find a record you could use Lambda in find, for example:

var results = collection.Find(x => x.name == "system").ToList();

Alternatively you can use Builders which work with strongly typed Lambda or text:

var filter = Builders<User>.Filter.Eq(x => x.name, "system")

Or

var filter = Builders<User>.Filter.Eq("name", "system")

And then use find as above

// results will be a collection of your documents matching your filter criteria

// Sync syntax
var results = collection.Find(filter).ToList();

// Async syntax
var results = await collection.Find(filter).ToListAsync();
Saturday, July 3, 2021
 
Oshrib
answered 4 Months ago
91

The simplest and safest way to do that is using Linq:

var names = namesCollection.AsQueryable().Where(name =>
    name.FirstName.ToLower().Contains("hamster"));

As explained in the tutorial ToLower, ToLowerInvariant, ToUpper and ToUpperInvariant all perform matches in a case insensitive way. After that you can use all the supported string methods like Contains or StartsWith.

This example will generate:

{
    "FirstName" : /hamster/is
}

The i option makes it case insensitive.

Monday, July 19, 2021
 
Null
answered 4 Months ago
11

In the example document, the "payment" values are given as strings which may not work as intended with the $lt command. For this response, I have converted them to integers.

Wildcard queries are not possible with MongoDB, so with the given document structure, the key (0,1,2, etcetera) of the sub-document must be known. For instance, the following query will work:

> db.test.find({"visits.2.payment":{$lt:35}})

However,

> db.test.find({"visits.payment":{$lt:35}})

Will not work in this case, and

> db.test.find({"visits.*.payment":{$lt:35}})

will also not return any results.

In order to be able to query the embedded "visits" documents, you must change your document structure and make "visits" into an array or embedded documents, like so:

> db.test2.find().pretty()
{
    "_id" : ObjectId("4f16199d3563af4cb141c547"),
    "dob" : "10-01-1998",
    "name" : "Sam",
    "visits" : [
        {
            "service_date" : "12-5-2011",
            "payment" : 30,
            "chk_number" : "86786464"
        },
        {
            "service_date" : "12-15-2011",
            "payment" : 35,
            "chk_number" : "45643461234"
        },
        {
            "service_date" : "12-25-2011",
            "payment" : 20,
            "chk_number" : "4569821234"
        }
    ]
}

Now you can query all of the embedded documents in "visits":

> db.test2.find({"visits.payment":{$lt:35}})

For more information, please refer to the Mongo documentation on dot notation:

http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

Now on to the second part of your question: it is not possible to return only a conditional sub-set of embedded documents.

With either document format, it is not possible to return a document containing ONLY the sub-documents that match the query. If one of the sub-documents matches the query , then the entire document matches the query, and it will be returned.

As per the Mongo Document "Retrieving a subset of fields"

http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields

We can return parts of embedded documents like so:

> db.test2.find({"visits.payment":{$lt:35}},{"visits.service_date":1}).pretty()
{
    "_id" : ObjectId("4f16199d3563af4cb141c547"),
    "visits" : [
        {
            "service_date" : "12-5-2011"
        },
        {
            "service_date" : "12-15-2011"
        },
        {
            "service_date" : "12-25-2011"
        }
    ]
}

But we cannot have conditional retrieval of some sub documents. The closest that we can get is the $slice operator, but this is not conditional, and you will have to first know the location of each sub-document in the array:

http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements

In order for the application to display only the embedded documents that match the query, it will have to be done programmatically.

Monday, October 4, 2021
 
LZN
answered 3 Weeks ago
LZN
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :