Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find empty object properties in MongoDb collection

Tags:

mongodb

How can I find all documents in a MongoDb collection where a property of the document or its sub-documents contains an empty object value {}? The name of the property is not known.

Example of which documents should be returned:

{
  data: {
      comment: {}
  }
}

As said data and comment as property names are unknown.

like image 227
Alexander Zeitler Avatar asked Mar 27 '18 12:03

Alexander Zeitler


People also ask

How do I check if a field is empty in MongoDB?

In MongoDB, we can check the existence of the field in the specified collection using the $exists operator. When the value of $exists operator is set to true, then this operator matches the document that contains the specified field(including the documents where the value of that field is null).

How do I query NULL values in MongoDB?

MongoDB fetch documents containing 'null' If we want to fetch documents from the collection "testtable" which contains the value of "interest" is null, the following mongodb command can be used : >db. testtable. find( { "interest" : null } ).

What does find () do in MongoDB?

Find() Method. In MongoDB, find() method is used to select documents in a collection and return a cursor to the selected documents.

How do I view collection data in MongoDB?

To get stats about MongoDB server, type the command db. stats() in MongoDB client. This will show the database name, number of collection and documents in the database.


1 Answers

The way to iterate object properties within aggregation pipeline is $objectToArray operator, which converts a document to the array of key-value pairs. Unfortunately, it does not flatten embedded documents. Until such support is implemented, I don't see a way to accomplish your task with the pure aggregation pipeline.

However you could always use $where operator and put the logic into JavaScript code. It should recursively iterate over all document properties and check whether the value is an empty document. Here is a working sample:

db.collection.find({"$where" : function () {

    function hasEmptyProperties(doc) {

        for (var property in doc) {
            var value = doc[property];
            if (value !== null && value.constructor === Object &&
                (Object.keys(value).length === 0 || hasEmptyProperties(value))) {
                return true;
            }
        }

        return false;
    }

    return hasEmptyProperties(this);

}});

If you fill the collection with the following data:

db.collection.insert({ _id: 1, p: false });
db.collection.insert({ _id: 2, p: [] });
db.collection.insert({ _id: 3, p: null });
db.collection.insert({ _id: 4, p: new Date() });
db.collection.insert({ _id: 5, p: {} });
db.collection.insert({ _id: 6, nestedDocument: { p: "Some Value" } });
db.collection.insert({ _id: 7, nestedDocument: { p1: 1, p2: {} } });
db.collection.insert({ _id: 8, nestedDocument: { deepDocument: { p: 1 } } });
db.collection.insert({ _id: 9, nestedDocument: { deepDocument: { p: {} } } });

the query will correctly detect all documents with empty properties:

{ "_id" : 5, "p" : {  } }
{ "_id" : 7, "nestedDocument" : { "p1" : 1, "p2" : {  } } }
{ "_id" : 9, "nestedDocument" : { "deepDocument" : { "p" : {  } } } }

Just for reference, here is an aggregation pipeline based on $objectToArray which detects empty properties, however not within nested documents:

db.collection.aggregate(
[
    { "$project": {
        _id: 1,
        "properties": { "$objectToArray": "$$ROOT" }
    }},

    { "$project": {
        _id: 1,
        propertyIsEmpty: { 
            $map: {
                input: "$properties.v",
                as: "value",
                in: { $eq: ["$$value", {} ] }
            }
        }
    }},

    { "$project": {
        _id: 1,
        anyPropertyIsEmpty: { $anyElementTrue: [ "$propertyIsEmpty" ] }
    }},

    {$match : {"anyPropertyIsEmpty" : true}},

    { "$project": {
        _id: 1,
    }},
]);
like image 66
CodeFuller Avatar answered Sep 18 '22 07:09

CodeFuller