Esempio n. 1
0
        // This process monitor and updates redundancy control of the driver instance in mongodb
        static async void ProcessRedundancyMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var lastActiveNodeKeepAliveTimeTag = DateTime.MinValue;
                    var countKeepAliveUpdates          = 0;
                    var countKeepAliveUpdatesLimit     = 4;
                    var Client = ConnectMongoClient(jsConfig);
                    var DB     = Client.GetDatabase(jsConfig.mongoDatabaseName);

                    // read and process instances configuration
                    var collinsts =
                        DB
                        .GetCollection
                        <protocolDriverInstancesClass
                        >(ProtocolDriverInstancesCollectionName);
                    do
                    {
                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        var collconns =
                            DB
                            .GetCollection
                            <IEC10X_connection
                            >(ProtocolConnectionsCollectionName);
                        var instances =
                            collinsts
                            .Find(inst =>
                                  inst.protocolDriver == ProtocolDriverName &&
                                  inst.protocolDriverInstanceNumber == ProtocolDriverInstanceNumber)
                            .ToList();
                        var foundinstance = false;
                        foreach (protocolDriverInstancesClass inst in instances)
                        {
                            foundinstance = true;

                            var nodefound = false;
                            foreach (var name in inst.nodeNames)
                            {
                                if (JSConfig.nodeName == name)
                                {
                                    nodefound = true;
                                }
                            }
                            if (!nodefound)
                            {
                                Log("Node '" +
                                    JSConfig.nodeName +
                                    "' not found in instances configuration!");
                                Environment.Exit(-1);
                            }

                            if (inst.activeNodeName == JSConfig.nodeName)
                            {
                                if (!Active) // will go active
                                {
                                    Log("Redundancy - ACTIVATING this Node!");
                                }
                                Active = true;
                                countKeepAliveUpdates = 0;
                            }
                            else
                            {
                                if (Active) // will go inactive
                                {           // wait a random time
                                    Log("Redundancy - DEACTIVATING this Node (other node active)!");
                                    countKeepAliveUpdates = 0;
                                    Random rnd = new Random();
                                    Thread.Sleep(rnd.Next(1000, 5000));
                                }
                                Active = false;
                                if (lastActiveNodeKeepAliveTimeTag == inst.activeNodeKeepAliveTimeTag)
                                {
                                    countKeepAliveUpdates++;
                                }
                                lastActiveNodeKeepAliveTimeTag = inst.activeNodeKeepAliveTimeTag;
                                if (countKeepAliveUpdates > countKeepAliveUpdatesLimit)
                                { // time exceeded, be active
                                    Log("Redundancy - ACTIVATING this Node!");
                                    Active = true;
                                }
                            }

                            if (Active)
                            {
                                Log("Redundancy - This node is active.");

                                // update keep alive time
                                var filter1 =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .Eq(m => m.protocolDriver,
                                        ProtocolDriverName);

                                var filter2 =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .Eq(m => m.protocolDriverInstanceNumber,
                                        ProtocolDriverInstanceNumber);

                                var filter =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .And(filter1, filter2);

                                var update =
                                    Builders <protocolDriverInstancesClass>
                                    .Update
                                    .Set(m => m.activeNodeName, JSConfig.nodeName)
                                    .Set(m => m.activeNodeKeepAliveTimeTag, DateTime.Now);

                                var options =
                                    new FindOneAndUpdateOptions <protocolDriverInstancesClass, protocolDriverInstancesClass
                                                                 >();
                                options.IsUpsert = false;
                                await collinsts
                                .FindOneAndUpdateAsync(filter, update, options);

                                // update statistics for connections
                                foreach (IEC10X_connection srv in IEC10Xconns)
                                {
                                    if (!(srv.connection is null))
                                    {
                                        var stats = srv.connection.GetStatistics();
                                        var filt  =
                                            new BsonDocument(new BsonDocument("protocolConnectionNumber",
                                                                              srv.protocolConnectionNumber));
                                        var upd =
                                            new BsonDocument("$set", new BsonDocument {
                                            { "stats", new BsonDocument {
                                                  { "nodeName", JSConfig.nodeName },
                                                  { "timeTag", BsonDateTime.Create(DateTime.Now) },
                                                  { "isConnected", BsonBoolean.Create(srv.connection.IsRunning) },
                                                  { "rcvdMsgCounter", BsonDouble.Create(stats.RcvdMsgCounter) },
                                                  { "sentMsgCounter", BsonDouble.Create(stats.SentMsgCounter) },
                                                  { "rcvdTestFrActCounter", BsonDouble.Create(stats.RcvdTestFrActCounter) },
                                                  { "rcvdTestFrConCounter", BsonDouble.Create(stats.RcvdTestFrConCounter) }
                                              } },
                                        });
                                        var res = collconns.UpdateOneAsync(filt, upd);
                                    }
                                }
                            }
                            else
                            {
                                if (inst.activeNodeName != "")
                                {
                                    Log("Redundancy - This node is INACTIVE! Node '" + inst.activeNodeName + "' is active, wait...");
                                }
                                else
                                {
                                    Log("Redundancy - This node is INACTIVE! No node is active, wait...");
                                }
                            }

                            break; // process just first result
                        }

                        if (!foundinstance)
                        {
                            if (Active) // will go inactive
                            {           // wait a random time
                                Log("Redundancy - DEACTIVATING this Node (no instance found)!");
                                countKeepAliveUpdates = 0;
                                Random rnd = new Random();
                                Thread.Sleep(rnd.Next(1000, 5000));
                            }
                            Active = false;
                        }

                        Thread.Sleep(5000);
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);
                }
            }while (true);
        }
        public void TestClassWithBsonValueId()
        {
            // repeats all tee TestClassWithBsonXyzId tests using ClassWithBsonValueId
            {
                // same as TestClassWithBonArrayId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = new BsonArray(), X = 1
                };
                Assert.Throws <MongoSafeModeException>(() => { _collection.Insert(doc); });

                doc = new ClassWithBsonValueId {
                    Id = new BsonArray {
                        1, 2, 3
                    }, X = 1
                };
                Assert.Throws <MongoSafeModeException>(() => { _collection.Insert(doc); });
            }

            {
                // same as TestClastWithBsonBinaryDataId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonBinaryData.Create(new byte[] { }), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonBinaryData.Create(new byte[] { 1, 2, 3 }), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonBooleanId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonBoolean.Create(false), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonBoolean.Create(true), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonDocumentId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = new BsonDocument(), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = new BsonDocument {
                        { "A", 1 }, { "B", 2 }
                    }, X = 3
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonDateTimeId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonDateTime.Create(DateTime.MinValue), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonDateTime.Create(DateTime.UtcNow), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonDateTime.Create(DateTime.MaxValue), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonDoubleId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonDouble.Create(0.0), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonDouble.Create(1.0), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonInt32Id
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonInt32.Create(0), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonInt32.Create(1), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonInt64Id
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonInt64.Create(0), X = 1
                };
                _collection.Insert(doc);

                doc = new ClassWithBsonValueId {
                    Id = BsonInt64.Create(1), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonMaxKeyId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual(null, doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = BsonMaxKey.Value, X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonMinKeyId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual(null, doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = BsonMinKey.Value, X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonNullId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual(null, doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = BsonNull.Value, X = 1
                };
                Assert.Throws <MongoSafeModeException>(() => { _collection.Insert(doc); });
            }

            {
                // same as TestClassWithBsonObjectId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.IsNull(doc.Id); // BsonObjectIdGenerator is not invoked when nominalType is BsonValue

                doc = new ClassWithBsonValueId {
                    Id = BsonObjectId.Empty, X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual(ObjectId.Empty, doc.Id.AsObjectId); // BsonObjectIdGenerator is not invoked when nominalType is BsonValue

                doc = new ClassWithBsonValueId {
                    Id = BsonObjectId.GenerateNewId(), X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonStringId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.IsNull(doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = "", X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual("", doc.Id.AsString);

                doc = new ClassWithBsonValueId {
                    Id = "123", X = 1
                };
                _collection.Insert(doc);
            }

            {
                // same as TestClassWithBsonTimestampId
                _collection.RemoveAll();

                var doc = new ClassWithBsonValueId {
                    Id = null, X = 1
                };
                _collection.Insert(doc);
                Assert.IsNull(doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = BsonTimestamp.Create(0, 0), X = 1
                };
                _collection.Insert(doc);
                Assert.AreEqual(BsonTimestamp.Create(0, 0), doc.Id);

                doc = new ClassWithBsonValueId {
                    Id = BsonTimestamp.Create(1, 2), X = 1
                };
                _collection.Insert(doc);
            }
        }
Esempio n. 3
0
        public static BsonValue Create(this BsonType bsonType, object o)
        {
            BsonValue value = BsonNull.Value;

            try
            {
                switch (bsonType)
                {
                case BsonType.EndOfDocument:
                    break;

                case BsonType.Double:
                    value = BsonDouble.Create(o);
                    break;

                case BsonType.String:
                    value = BsonString.Create(o);
                    break;

                case BsonType.Document:
                    value = BsonDocument.Create(o);
                    break;

                case BsonType.Array:
                    value = BsonArray.Create(o);
                    break;

                case BsonType.Binary:
                    value = BsonBinaryData.Create(o);
                    break;

                case BsonType.Undefined:
                    break;

                case BsonType.ObjectId:
                    value = BsonObjectId.Create(o);
                    break;

                case BsonType.Boolean:
                    value = BsonBoolean.Create(o);
                    break;

                case BsonType.DateTime:
                    value = BsonDateTime.Create(o);
                    break;

                case BsonType.Null:
                    value = BsonNull.Value;
                    break;

                case BsonType.RegularExpression:
                    value = BsonRegularExpression.Create(o);
                    break;

                case BsonType.JavaScript:
                    value = BsonJavaScript.Create(o);
                    break;

                case BsonType.Symbol:
                    value = BsonSymbol.Create(o);
                    break;

                case BsonType.JavaScriptWithScope:
                    value = BsonJavaScriptWithScope.Create(o);
                    break;

                case BsonType.Int32:
                    value = BsonInt32.Create(o);
                    break;

                case BsonType.Timestamp:
                    value = BsonTimestamp.Create(o);
                    break;

                case BsonType.Int64:
                    value = BsonInt64.Create(o);
                    break;

                case BsonType.MaxKey:
                    value = BsonValue.Create(o);
                    break;

                case BsonType.MinKey:
                    value = BsonValue.Create(o);
                    break;
                }
            }
            catch
            {
            }

            return(value);
        }
Esempio n. 4
0
        // This process updates acquired values in the mongodb collection for realtime data
        static public async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    Log("MongoDB Update Thread Started...");

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        //if (LogLevel >= LogLevelBasic && OPCDataQueue.Count > 0)
                        //  Log("MongoDB - Data queue size: " +  OPCDataQueue.Count, LogLevelBasic);

                        // Log("1");

                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        // Log("2");
                        IEC_CmdAck ia;
                        if (OPCCmdAckQueue.Count > 0)
                        {
                            while (OPCCmdAckQueue.TryDequeue(out ia))
                            {
                                var filter1 =
                                    Builders <rtCommand>
                                    .Filter
                                    .Eq(m => m.protocolSourceConnectionNumber,
                                        ia.conn_number);

                                var filter2 =
                                    Builders <rtCommand>
                                    .Filter
                                    .Eq(m => m.protocolSourceObjectAddress,
                                        ia.object_address);

                                var filter =
                                    Builders <rtCommand>
                                    .Filter
                                    .And(filter1, filter2);

                                var update =
                                    Builders <rtCommand>
                                    .Update
                                    .Set(m => m.ack, ia.ack)
                                    .Set(m => m.ackTimeTag, ia.ack_time_tag);

                                // sort by priority then by insert order
                                var sort =
                                    Builders <rtCommand> .Sort.Descending("$natural");

                                var options =
                                    new FindOneAndUpdateOptions <rtCommand, rtCommand
                                                                 >();
                                options.IsUpsert = false;
                                options.Sort     = sort;
                                await collection_cmd
                                .FindOneAndUpdateAsync(filter, update, options);
                            }
                        }
                        // Log("3");

                        Stopwatch stopWatch = new Stopwatch();
                        stopWatch.Start();

                        OPC_Value iv;
                        while (!OPCDataQueue.IsEmpty && OPCDataQueue.TryPeek(out iv) && OPCDataQueue.TryDequeue(out iv))
                        {
                            // Log("3.1");
                            DateTime  tt     = DateTime.MinValue;
                            BsonValue bsontt = BsonNull.Value;
                            try
                            {
                                if (iv.hasSourceTimestamp)
                                {
                                    bsontt = BsonValue.Create(iv.sourceTimestamp);
                                }
                            }
                            catch
                            {
                                tt     = DateTime.MinValue;
                                bsontt = BsonNull.Value;
                            }

                            BsonDocument valJSON = new BsonDocument();
                            try
                            {
                                valJSON = BsonDocument.Parse(iv.valueJson);
                            }
                            catch (Exception e)
                            {
                                Log(iv.conn_name + " - " + e.Message);
                            }

                            // Log("3.2");

                            if (iv.selfPublish)
                            {
                                string tag = TagFromOPCParameters(iv);
                                if (!InsertedTags.Contains(tag))
                                {
                                    // look for the tag
                                    var task = await collection.FindAsync <rtData>(new BsonDocument {
                                        {
                                            "tag", TagFromOPCParameters(iv)
                                        }
                                    });

                                    List <rtData> list = await task.ToListAsync();

                                    // await Task.Delay(10);
                                    //Thread.Yield();
                                    //Thread.Sleep(1);

                                    InsertedTags.Add(tag);
                                    if (list.Count == 0)
                                    {
                                        Log(iv.conn_name + " - INSERT - " + iv.address);
                                        // hash to create keys
                                        var id         = HashStringToInt(iv.address);
                                        var insert     = newRealtimeDoc(iv, id);
                                        int conn_index = 0;
                                        // normal for loop
                                        for (int index = 0; index < OPCUAconns.Count; index++)
                                        {
                                            if (OPCUAconns[index].protocolConnectionNumber == iv.conn_number)
                                            {
                                                conn_index = index;
                                            }
                                        }
                                        insert.protocolSourcePublishingInterval = OPCUAconns[conn_index].autoCreateTagPublishingInterval;
                                        insert.protocolSourceSamplingInterval   = OPCUAconns[conn_index].autoCreateTagSamplingInterval;
                                        insert.protocolSourceQueueSize          = OPCUAconns[conn_index].autoCreateTagQueueSize;
                                        listWrites
                                        .Add(new InsertOneModel <rtData>(insert));
                                    }
                                }
                            }

                            //below code will update one record of the data
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueBsonAtSource", valJSON
                                                },
                                                {
                                                    "valueAtSource",
                                                    BsonDouble
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonString
                                                    .Create(iv.valueString)
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonString
                                                    .Create(iv.asdu.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonString.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTagAtSource",
                                                    bsontt
                                                },
                                                {
                                                    "timeTagAtSourceOk",
                                                    BsonBoolean
                                                    .Create(iv.hasSourceTimestamp)
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv
                                                            .serverTimestamp)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonBoolean
                                                    .Create(!iv
                                                            .quality
                                                            )
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceCommonAddress =
                                    iv.common_address,
                                protocolSourceObjectAddress = iv.address
                            };
                            Log("MongoDB - ADD " + iv.address + " " + iv.value,
                                LogLevelDebug);
                            // Log("3.3");

                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));

                            if (listWrites.Count >= BulkWriteLimit)
                            {
                                break;
                            }

                            if (stopWatch.ElapsedMilliseconds > 400)
                            {
                                break;
                            }

                            // Log("3.4 - Write buffer " + listWrites.Count + " Data " + OPCDataQueue.Count);

                            // give time to breath each 250 dequeues
                            //if ((listWrites.Count % 250)==0)
                            //{
                            //   await Task.Delay(10);
                            //Thread.Yield();
                            //Thread.Sleep(1);
                            //}
                        }

                        // Log("4");
                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk write " + listWrites.Count + " Data " + OPCDataQueue.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();

                            //Thread.Yield();
                            //Thread.Sleep(1);
                        }

                        if (OPCDataQueue.IsEmpty)
                        {
                            await Task.Delay(250);
                        }
                        // Log("6");
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    Thread.Sleep(1000);

                    while (OPCDataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("MongoDB - Dequeue Data", LogLevelDetailed);
                        OPC_Value iv;
                        OPCDataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Esempio n. 5
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="value"></param>
 /// <returns></returns>
 public static BsonValue Boolean(object value)
 {
     return(BsonBoolean.Create((bool)value));
 }
Esempio n. 6
0
 /// <summary>
 /// Adds a $exist test to the query.
 /// </summary>
 /// <param name="exists">Whether to test for the existence or absence of an element.</param>
 /// <returns>The builder (so method calls can be chained).</returns>
 public QueryNotConditionList Exists(
     bool exists
     )
 {
     return(new QueryNotConditionList(name, "$exists", BsonBoolean.Create(exists)));
 }